Aller au contenu principal

Prettier 1.6 : Fichier de configuration et JSX

· 16 minutes de lecture
Traduction Bêta Non Officielle

Cette page a été traduite par PageTurner AI (bêta). Non approuvée officiellement par le projet. Vous avez trouvé une erreur ? Signaler un problème →

Cette version ajoute le support des fichiers de configuration à Prettier, ainsi que des améliorations significatives pour le formatage JSX.

Je tiens à remercier chaleureusement @azz qui a maintenu le dépôt et implémenté de nombreux changements de cette version, car j'ai eu moins de temps à consacrer à Prettier en raison de vacances et d'un changement d'équipe :)

Principales fonctionnalités

Configuration

Implémentation de cosmiconfig pour la configuration d'espace de travail (#2434) par @azz

Dès la première version de Prettier, les utilisateurs ont demandé un fichier .prettierrc. Nous avons toujours cherché à avoir le moins d'options possible et à éviter d'être un .dotfile supplémentaire nécessaire au démarrage d'un projet.

Mais en réalité, nous avons besoin d'un moyen de configurer Prettier qui puisse rester synchronisé avec toutes les intégrations. En n'en ayant pas, nous avons reporté le problème sur ces intégrations et observé plusieurs approches incompatibles. Désormais, c'est Prettier lui-même qui gère cela.

// .prettierrc
{
"trailingComma": "es5",
"singleQuote": true
}

Pour plus d'informations sur le support des fichiers de configuration, consultez le README.

Support des fichiers .prettierignore (#2412) par @evilebottnawi

En plus d'indiquer la configuration à utiliser, vous pouvez écrire un fichier .prettierignore pour spécifier les fichiers à ne pas formater.

## .prettierignore
dist/
package.json

JSX

Amélioration du formatage JSX (#2398) par @suchipi

Le dernier point de friction important pour l'adoption de Prettier concernait l'affichage du JSX. Nous avons examiné toutes les problématiques soulevées et apporté plusieurs modifications :

  • Les expressions de fonction fléchée retournant du JSX ajoutent désormais des parenthèses quand le JSX s'étend sur plusieurs lignes
// Before
const Component = props =>
<div>
Hello {props.name}!
</div>;

// After
const Component = props => (
<div>
Hello {props.name}!
</div>
);
  • Les expressions conditionnelles dans (ou contenant) du JSX sont désormais formatées différemment avec des parenthèses
// Before
<div>
{props.isVisible
? <BaseForm
url="/auth/google"
method="GET"
/>
: <Placeholder />}
</div>;

// After
<div>
{props.isVisible ? (
<BaseForm
url="/auth/google"
method="GET"
/>
) : (
<Placeholder />
)}
</div>
  • Le JSX dans les expressions logiques (|| ou &&) est toujours entouré de parenthèses quand il s'étend sur plusieurs lignes
// Before
<div>
{props.isVisible &&
<BaseForm
url="/auth/google"
method="GET"
/>}
</div>;

// After
<div>
{props.isVisible && (
<BaseForm
url="/auth/google"
method="GET"
/>
)}
</div>

Ces changements devraient mieux correspondre aux pratiques de la communauté et permettre à Prettier d'être utilisé dans plus de projets ;)

Intégration des expressions simples dans le JSX (#2442) par @karl

Initialement avec JSX, nous respections beaucoup de sauts de ligne présents dans le code source. Cette approche avait l'avantage de modifier moins votre base de code, mais elle nuisait à la cohérence du formateur puisque le même code sémantique pouvait s'écrire de deux façons.

À chaque nouvelle version, nous avons affiné ce comportement et pris des décisions pour normaliser l'affichage. La dernière en date concerne les enfants uniques dans un objet JSX : nous les intégrons systématiquement sur une seule ligne.

// Before
return (
<div>
{this.props.test}
</div>
);
return <div>{this.props.test}</div>;

// After
return <div>{this.props.test}</div>;
return <div>{this.props.test}</div>;

Ajout systématique d'un saut de ligne après les espaces initiaux en JSX (#2348) par @karl

Les espaces vides initiaux en JSX sont désormais placés sur leur propre ligne. Leur présence devant une balise créait un effet d'indentation incohérent avec le reste.

// Before
<span className="d1">
{' '}<a
href="https://github.schibsted.io/finn/troika"
className="link"
/>
</span>

// After
<span className="d1">
{' '}
<a
href="https://github.schibsted.io/finn/troika"
className="link"
/>
</span>

Autres changements

JSON

Utiliser babylon.parseExpression pour JSON (#2476) par @josephfrazier

Nous utilisions auparavant un analyseur JSON strict qui émettait une erreur en présence de commentaires ou de virgules finales. Cela était gênant car de nombreux fichiers JSON sont en pratique analysés avec JavaScript ou json5, moins stricts. Nous avons assoupli cette règle et utilisons désormais l'analyseur JavaScript pour traiter le JSON. Ainsi, les commentaires seront conservés s'ils existent.

Notez que ce changement est purement additif : si votre fichier d'origine était conforme au JSON standard, il continuera à produire un JSON valide.

// Before
Syntax error

// After
{ /* some comment */ "a": 1 }

JavaScript

Imprimer les chaînages de 3 appels ou plus sur plusieurs lignes (#2673) par @azz

C'était un problème récurrent dans l'impression des longues chaînes d'appels. Prettier tentait de tout compresser sur une seule ligne sauf le dernier callback, ce qui nuisait à la lisibilité. La solution retenue consiste à toujours passer à la ligne pour les chaînages comportant trois appels de fonction ou plus.

// Before
Promise.resolve(0).catch(function(err) {}).then(function(res) {
//
});

// After
Promise.resolve(0)
.catch(function(err) {})
.then(function(res) {
//
});

Ajouter davantage de parenthèses de supervision (#2423) par @azz

Les parenthèses sont un sujet sensible car absentes de l'AST : Prettier ignore celles que vous ajoutez et les recrée intégralement. Nous avons examiné les cas remontés et identifié des cas limites déroutants lorsque des comparaisons étaient chaînées ou que % se mélangeait à * ou /.

Nous conservons cependant la suppression des parenthèses superflues autour des combinaisons d'opérateurs arithmétiques de base : +-*/.

// Before
x !== y === z;
x * y % z;

// After
(x !== y) === z;
(x * y) % z;

Implémenter prettier-ignore dans JSX (#2487) par @azz

Ignorer des portions de JSX est désormais possible en ajoutant un commentaire à l'intérieur d'une expression JSX pour préserver la mise en forme de l'élément suivant.

// Before
<Component>
{/*prettier-ignore*/}
<span ugly format="" />
</Component>

// Before
<Component>
{/*prettier-ignore*/}
<span ugly format='' />
</Component>

Ne pas supprimer les commentaires prettier-ignore (#2664)

Pour gérer certains cas limites, notre mécanisme interne évitait d'imprimer les commentaires génériquement pour les traiter ultérieurement. Or, les commentaires prettier-ignore n'étaient tout simplement pas imprimés ! Ce problème est maintenant résolu.

// Before
push(
<td> :)
</td>,
);

// After
push(
// prettier-ignore
<td> :)
</td>,
);

Corriger l'indentation des conditions do-while (#2359) par @jsnajdr

Il a fallu six mois pour que quelqu'un signale que les do-while étaient cassés avec des conditions multi-lignes, ce qui confirme mon intuition que cette structure est peu utilisée en pratique.

// Before
do {} while (
someVeryLongFunc(
someVeryLongArgA,
someVeryLongArgB,
someVeryLongArgC
)
);

// After
do {} while (
someVeryLongFunc(
someVeryLongArgA,
someVeryLongArgB,
someVeryLongArgC
)
);

Gérer les expressions séquentielles multi-lignes (#2388) par @bakkot

Les expressions séquentielles sont une autre fonctionnalité sous-utilisée de JavaScript. Leur impression en multi-lignes était défectueuse, ce qui a été corrigé :)

// Before
(a = b ? c : "lllllllllllllllllllllll"), (a = b
? c
: "lllllllllllllllllllllll"), (a = b ? c : "lllllllllllllllllllllll"), (a = b
? c
: "lllllllllllllllllllllll"), (a = b ? c : "lllllllllllllllllllllll");

// After
(a = b ? c : 'lllllllllllllllllllllll'),
(a = b ? c : 'lllllllllllllllllllllll'),
(a = b ? c : 'lllllllllllllllllllllll'),
(a = b ? c : 'lllllllllllllllllllllll'),
(a = b ? c : 'lllllllllllllllllllllll')

Supprimer les espaces de fin dans les commentaires (#2494) par @azz

Notre position chez Prettier est de supprimer tous les espaces de fin. Nous évitions de toucher aux commentaires car générés par l'utilisateur, mais cela ne justifie pas d'y conserver des espaces superflus :)

// Before
// There is some space here ->______________

// After
// There is some space here ->

Corriger les commentaires entrelacés dans les décorateurs de classe (#2660, #2661)

Notre gestion des commentaires dans les déclarations de classe était très naïve : nous les déplacions systématiquement en haut. Nous sommes désormais plus précis et respectons les commentaires intercalés dans les décorateurs et autour de extends.

// Before
// A
// B
// C
@Foo()
@Bar()
class Bar {}

// After
// A
@Foo()
// B
@Bar()
// C
class Bar {}

Amélioration du formatage des expressions bind (#2493) par @azz

Les expressions bind sont discutées au TC39 et nous avons pensé pouvoir les formater avec Prettier. Notre approche était très basique : nous les chaînions simplement. Maintenant, nous appliquons la même logique que pour le chaînage de méthodes avec l'opérateur .. Nous avons aussi corrigé certains cas limites où cela produisait du code invalide.

// Before
observable::filter(data => data.someTest)::throttle(() =>
interval(10)::take(1)::takeUntil(observable::filter(data => someOtherTest))
)::map(someFunction);

// After
observable
::filter(data => data.someTest)
::throttle(() =>
interval(10)::take(1)::takeUntil(observable::filter(data => someOtherTest))
)
::map(someFunction);

Ajout du support pour le paramètre optionnel de catch (#2570) par @existentialism

Le TC39 discute actuellement de rendre optionnel l'argument de catch(e). Assurons-nous que Prettier puisse le prendre en charge si les développeurs l'utilisent.

// Before
Syntax error

// After
try {} catch {}

Ajout du support pour la syntaxe de chaînage optionnel (#2572) par @azz

Une autre nouvelle proposition discutée au TC39 concerne la syntaxe de chaînage optionnel. C'est actuellement une proposition de stage 1, donc sa syntaxe peut encore évoluer.

obj?.prop       // optional static property access
obj?.[expr] // optional dynamic property access
func?.(...args) // optional function or method call

Gestion correcte de la syntaxe de transtypage de Closure Compiler (#2484) par @yangsu

Les commentaires sont complexes à gérer, surtout lorsqu'ils ont une signification selon leur position. Nous traitons désormais spécifiquement les commentaires utilisés comme transtypage pour Closure Compiler afin qu'ils conservent leur sémantique.

// Before
let assignment /** @type {string} */ = getValue();

// After
let assignment = /** @type {string} */ (getValue());

Intégration en ligne de la première propriété calculée dans une chaîne (#2670) par @azz

Avoir une recherche de propriété calculée sur une nouvelle ligne paraissait étrange, nous avons donc ajouté un cas spécifique pour l'intégrer en ligne.

// Before
data
[key]('foo')
.then(() => console.log('bar'))
.catch(() => console.log('baz'));

// After
data[key]('foo')
.then(() => console.log('bar'))
.catch(() => console.log('baz'));

Flow

Support des types opaques et des exports étoiles (#2543, #2542) par @existentialism

L'équipe Flow a introduit deux fonctionnalités majeures avec une nouvelle syntaxe. Prettier les prend désormais en charge. Personnellement, j'attendais les types opaques depuis très longtemps !

// Before
Syntax error

// After
opaque type ID = string;
export type * from "module";

Suppression des guillemets superflus dans les clés des objets de type et interfaces (#2643) par @jackyho112

Nous faisions cela pour les objets JavaScript depuis les débuts de Prettier, mais avions oublié de l'appliquer aux types Flow et TypeScript.

// Before
type A = {
"string": "A";
}

// After
type A = {
string: "A";
}

Impression du TypeParameter même pour les fonctions unaires (#2406) par @danwang

Oups, nous omettions le générique dans ce cas très spécifique.

// Before
type myFunction = A => B;

// After
type myFunction = <T>(A) => B;

Conservation des parenthèses autour des FunctionTypeAnnotation dans les ArrayTypeAnnotation (#2561) par @azz

Les parenthèses... un jour nous les aurons toutes corrigées :)

// Before
const actionArray: () => void[] = [];

// After
const actionArray: (() => void)[] = [];

TypeScript

Prise en charge de TypeScript 2.5 RC (#2672) par @azz

TypeScript 2.5 RC a été récemment annoncé, vous permettant d'utiliser la syntaxe "optional catch binding" à venir dans TypeScript également. 🎉

Ne pas ajouter le mot-clé namespace aux déclarations globales (#2329) par @azz

// Before
namespace global {
export namespace JSX { }
}

// After
global {
export namespace JSX {}
}

Correction de <this.Component /> (#2472) par @backus

Grâce à la nature non typée et permissive de JavaScript, nous avons pu concaténer undefined à une chaîne de caractères et obtenir un code intéressant. Ce cas est maintenant corrigé :)

// Before
<undefined.Author />

// After
<this.Author />

Permettre aux assertions de type d'être compactées (#2439) par @azz

Nous voulons nous assurer que tous les cas spéciaux ajoutés pour JavaScript et Flow fonctionnent également pour les constructions TypeScript. Dans ce cas, les objets doivent aussi être compactés s'ils sont encapsulés dans un opérateur as.

// Before
const state = JSON.stringify(
{
next: window.location.href,
nonce,
} as State
);

// After
const state = JSON.stringify({
next: window.location.href,
nonce,
} as State);

Suppression des parenthèses pour les assertions de type dans les expressions binaires (#2419) par @azz

La plupart du temps nous ajoutons des parenthèses pour la correction syntaxique, mais ici elles étaient superflues. Nous pouvons donc les supprimer pour un code plus propre :)

// Before
(<x>a) || {};

// After
<x>a || {};

Imprimer des parenthèses autour des assertions de type comme LHS dans les assignations (#2525) par @azz

Encore un cas de parenthèses manquantes. Heureusement, ils deviennent très rares aujourd'hui et concernent des cas extrêmement marginaux.

// Before
foo.bar as Baz = [bar];

// After
(foo.bar as Baz) = [bar];

Imprimer declare pour TSInterfaceDeclaration (#2574) par @existentialism

Le mot-clé declare ne fait rien pour les interface, donc nous ne l'ajoutions jamais. Cependant, c'était étrange dans les fichiers de déclaration où tout avait declare sauf les interfaces. Nous réimprimons désormais declare s'il était présent initialement.

// Before
interface Dictionary<T> {
[index: string]: T
}

// After
declare interface Dictionary<T> {
[index: string]: T
}

CSS

Normalisation des guillemets en CSS (#2624) par @lydell

Pour la première version de CSS, nous conservions les guillemets originaux. Nous respectons désormais l'option singleQuote de Prettier. La difficulté était de garantir un code correct avec tous les échappements, caractères Unicode, emojis, et règles spéciales comme charset qui ne fonctionnent qu'avec des guillemets doubles...

// Before
div {
content: "abc";
}

// After
div {
content: 'abc';
}

Normalisation des nombres en CSS (#2627) par @lydell

Un autre domaine où nous réutilisons la logique JavaScript pour améliorer l'impression CSS.

// Before
foo {
border: 1px solid rgba(0., 0.0, .0, .3);
}

// After
foo {
border: 1px solid rgba(0, 0, 0, 0.3);
}

Ajout de guillemets aux valeurs d'attribut CSS non citées dans les sélecteurs (#2644) par @lydell

Les règles complexes des guillemets autour des attributs étant difficiles à retenir, nous les ajoutons systématiquement désormais.

// Before
a[id=test] {}

// After
a[id="test"] {}

Ajout de la prise en charge du mot-clé css (#2337) par @zanza00

// Before
const header = css`.top-bar {background: black;margin: 0;position: fixed;}`

// After
const header = css`
.top-bar {
background: black;
margin: 0;
position: fixed;
}
`;

Prise en charge de styled-components avec composant existant (#2552, #2619) par @azz

styled-components propose de nombreuses variantes pour étiqueter les littéraux de gabarit comme CSS. Ce n'est pas idéal de devoir encoder toutes ces méthodes dans Prettier, mais puisque nous avons commencé, autant le faire proprement.

styled(ExistingComponent)`
css: property;
`;

styled.button.attr({})`
border: rebeccapurple;
`;

Suppression des espaces dans le combinateur descendant (#2411) par @azz

Les analyseurs CSS que nous utilisons ne fournissent pas un arbre sémantique à 100% : dans de nombreux cas, ils abandonnent et nous renvoient simplement le contenu saisi. C'est à nous de veiller à nettoyer cela tout en conservant l'exactitude. Dans ce cas, nous imprimions les espaces entre les sélecteurs tels quels, mais nous savons qu'il est correct de toujours les remplacer par un seul espace.

// Before
.hello

.how-you-doin {
height: 42;
}

// After
.hello .how-you-doin {
height: 42;
}

Suppression du BOM avant l'analyse (#2373) par @azz

Je fais encore des cauchemars avec le BOM d'une vie antérieure. Heureusement, en 2017, ce n'est plus un gros problème car la plupart des outils en sont maintenant conscients. Merci @azz d'avoir corrigé ce cas particulier lié à l'analyse CSS.

// Before
[BOM]/* Block comment *
html {
content: "#{1}";
}
// After
[BOM]/* Block comment */
html {
content: "#{1}";
}

GraphQL

Ajout du support du formatage partiel pour GraphQL (#2319) par @josephfrazier

Si vous tentiez d'utiliser la fonction de formatage partiel dans un fichier GraphQL, cela provoquait une exception. Désormais, cela fonctionne à nouveau correctement et ne reformate que la portion sélectionnée.

Ajout de l'extension .gql pour l'analyse GraphQL (#2357) par @rrdelaney

Chez Facebook, nous utilisons l'extension .graphql, mais il semble que .gql soit également courante. Cela ne coûte pas grand-chose de la prendre en compte dans l'heuristique qui détermine quel analyseur utiliser.

CLI

Prise en charge de multiples motifs avec le motif d'ignorage (#2356) par @evilebottnawi

Il était déjà possible d'avoir plusieurs motifs globaux, mais ils étaient additifs. Avec cette modification, vous pouvez ajouter un motif global pour ignorer certains fichiers. Cela devrait être très pratique pour ignorer des dossiers profondément imbriqués.

prettier --write '{**/*,*}.{js,jsx,json}' '!vendor/**'

Faire fonctionner --list-different avec --stdin (#2393) par @josephfrazier

C'est un moyen pratique de savoir si Prettier imprimerait un morceau de code différemment. Nous avions déjà tous les concepts en place, il suffisait simplement de les connecter correctement.

$ echo 'call ( ) ;' | prettier --list-different
(stdin)
$ echo $?
1