Hoppa till huvudinnehållet

Prettier 1.4: Stöd för TypeScript och CSS

· 16 min att läsa
Inofficiell Beta-översättning

Denna sida har översatts av PageTurner AI (beta). Inte officiellt godkänd av projektet. Hittade du ett fel? Rapportera problem →

Den här versionen introducerar stöd för språken TypeScript, CSS, Less och SCSS i Prettier!

prettier-revolution-conf

Stöd för TypeScript

Detta är den mest efterfrågade funktionen för Prettier. Med version 1.4.0 kan du nu använda Prettier för att formatera dina .ts och .tsx-filer!

Prettier fungerar genom att använda projekt för att generera en AST-representation av koden och sedan skriva ut den. Både babylon (parsern som driver Babel) och flow producerar en AST som ungefär följer estree-formatet för JavaScript-delarna och har sedan specialnoder för Flow-specifika element.

TypeScript introducerar, på samma sätt som Flow, specialnoder för sin syntax. Tyvärr följer det inte estree-formatet för resten av JavaScript-språket. Detta sätter oss i en knepig situation med Prettier eftersom vi i princip skulle behöva forka den helt för att kunna skriva ut TypeScript.

Denna inkompatibilitet med AST är inget nytt problem - ett annat projekt som kämpat med detta är ESLint. Eftersom AST är annorlunda fungerar inga av ESLints regler. Tur för oss är att @JamesHenry och @soda0289 skrivit ett projekt kallat typescript-eslint-parser som tar en TypeScript-AST och konverterar den till ett estree-format, precis vad vi behöver för Prettier!

Efter att projektet integrerats i Prettier implementerade @azz, @despairblue och @Pajn alla TypeScript-specifika noder och säkerställde att de 13k testerna i TypeScript-testpaketet passerar. Detta var ett enormt arbete som äntligen är klart att användas :)

Vi testade Prettier på de största TypeScript-projekten vi kunde hitta på GitHub för att säkerställa att den skriver ut korrekt kod. Vi har ännu inte lagt mycket tid på att optimera kodformateringen, så om du ser något konstigt - skapa gärna ett ärende!

Stöd för CSS, Less och SCSS

Medan TypeScript är den mest efterfrågade funktionen i open source-kretsar är CSS den största önskan från Facebooks ingenjörer. När man väl vant sig vid att formatera kod i ett språk vill man göra det överallt!

Det visar sig att CSS är ett betydligt mindre språk än JavaScript, och stödet för det tog bara några dagar att implementera. Vi använder postcss av @ai som underliggande parser som kan hantera CSS, Less och SCSS. Vi förlitar oss också på postcss-values-parser, postcss-selector-parser av @ben-eb och postcss-media-query-parser av @dryoma.

Tyvärr hanterar postcss för närvarande varken Sass eller Stylus. Vi skulle gärna lägga till stöd för dessa om någon är villig att implementera utskriftsfunktionen.

Observera att Prettier för närvarande endast formaterar koden - den respekterar ännu inte inställningar som singleQuote och utför inte färg- eller talnormalisering som vi gör för JavaScript.

Editorintegration

Projektets första fas gick ut på att få Prettier att producera korrekt och snygg kod. Nu när den är i bra skick kan vi ägna tid åt att förbättra integrationerna. Vi har precis lagt till stöd för två fantastiska funktioner: bibehållande av markörposition och möjlighet att formatera ett intervall istället för hela filen.

Observera att vi precis lagt till stödet i själva prettier, inga av redigeringsintegrationsverktygen använder det ännu. Dessutom har vi inte testat dem i praktiken så vi kommer troligtvis behöva fixa till vissa kantfall!

Lägg till cursorOffset-alternativ för markörpositionering (#1637) av @josephfrazier

För närvarande låter vi redigeringsverktygen beräkna markörpositionen, vilket de gör hyfsat bra. Men eftersom vi skriver ut koden kan vi ge den korrekta positionen!

Lägg till --range-start/end-flaggor för att formatera endast delar av inmatningen (#1609) av @josephfrazier

Detta är en ofta efterfrågad funktion. För närvarande formaterar prettier endast hela filer. Nu går det att formatera ett specifikt intervall.

Sättet det fungerar på är genom att traversera uppåt i AST-trädet för att hitta närmaste giltiga sats. På så sätt behöver du inte markera exakt rätt intervall. Du kan dra över det ungefärliga kodområdet du vill formatera, så löser prettier resten!

Lägg till filepath-flagga för att möjliggöra filtypsinferens (#1835) av @mitermayer

Eftersom vi nu formaterar CSS och TypeScript är det opraktiskt att behöva ange parser för varje fil. Nu kan du skicka med filens sökväg så kommer prettier läsa filändelsen och välja rätt parser automatiskt.

Höjdpunkter

Radbryt textinnehåll inom JSX (#1120, #1671, #1827, #1829) av @karl

Den största kvarvarande klagomålet med prettiers JSX-hantering var textutskrift. Tidigare lade den till fula {" "}-uttryck och ignorerade långa rader. Nu behandlar vi varje ord som en token och kan bryta texten korrekt.

Detta är ett fantastiskt arbete av @karl som inte bara implementerade funktionen utan även introducerade en ny primitiv i prettier för att hantera elementsekvenser som bryts vid kantträff.

// Before
<div>
Please state your
{" "}
<b>name</b>
{" "}
and
{" "}
<b>occupation</b>
{" "}
for the board of directors.
</div>

// After
<div>
Please state your <b>name</b> and <b>occupation</b> for the board of
directors.
</div>

Ta bort parenteser för JSX inom pilfunktioner (#1733) av @xixixao

Utvecklare som skriver funktionella komponenter kommer uppskatta detta. Vi lägger inte längre till parenteser för pilfunktioner som returnerar JSX.

// Before
const render1 = ({ styles }) => (
<div style={styles}>
Keep the wrapping parens. Put each key on its own line.
</div>
);

// After
const render1 = ({ styles }) =>
<div style={styles}>
Keep the wrapping parens. Put each key on its own line.
</div>;

Förbättra utskrift av malliteraler (#1664, #1714) av @josephfrazier

Utskrift av malliteraler har alltid varit utmanande för prettier. I version 1.3.0 förbättrade vi situationen avsevärt och med denna release hanterar vi alla vanliga fall på ett bra sätt.

Tidigare lade vi till en funktion som tog bort tomma rader, men detta gav ibland konstiga resultat - den är nu borttagen. En annan förbättring är att vi nu indentering vid raden där ${ börjar istället för vid ${-tecknet självt.

Berätta gärna om du fortfarande har problem med hur malliteraler formateras efter denna release!

// Before
const Bar = styled.div`
color: ${props => (props.highlight.length > 0 ? palette([
'text',
'dark',
'tertiary'
])(props) : palette([
'text',
'dark',
'primary'
])(props))} !important;
`

// After
const Bar = styled.div`
color: ${props =>
props.highlight.length > 0
? palette(["text", "dark", "tertiary"])(props)
: palette(["text", "dark", "primary"])(props)} !important;
`

Använd samma brytningsregler för tilldelningar och objektvärden (#1721)

Vi har finjusterad logik för hur radbrytningar ska hanteras efter tilldelningar (t.ex. a = ...). Denna logik tillämpas nu även för objektvärden. Detta bör hjälpa vid flerradig boolesk logik eller stora villkorsuttryck. Det är också ett bra exempel på hur vi kan skapa en konsekvent utskriftsmotor.

// Before
const o = {
somethingThatsAReallyLongPropName: this.props.cardType ===
AwesomizerCardEnum.SEEFIRST,
};

// After
const o = {
somethingThatsAReallyLongPropName:
this.props.cardType === AwesomizerCardEnum.SEEFIRST,
};

Indentera villkor inom !() (#1731)

Det har kommit en stadig ström av klagomål om tidigare rendering och det låg på listan över "kanske svårt att fixa, kollar senare". Det visade sig vara superenkelt, så här har du lösningen!

// Before
const anyTestFailures = !(aggregatedResults.numFailedTests === 0 &&
aggregatedResults.numRuntimeErrorTestSuites === 0);

// After
const anyTestFailures = !(
aggregatedResults.numFailedTests === 0 &&
aggregatedResults.numRuntimeErrorTestSuites === 0
);

Formatteringsfixar

Placera loopkroppar på samma rad när möjligt (#1498)

Vi gjorde redan detta för if-satser - nu gör vi konsekvent samma sak för loopar.

// Before
for (a in b)
var c = {};

// After
for (a in b) var c = {};

Fixa tom rad med Flow-union (#1511) av @existentialism

Vi ska inte indentera saker två gånger ;)

// Before
type Foo = Promise<

| { ok: true, bar: string, baz: SomeOtherLongType }
| { ok: false, bar: SomeOtherLongType }
>;

// After
type Foo = Promise<
{ ok: true, bar: string, baz: SomeOtherLongType } |
{ ok: false, bar: SomeOtherLongType }
>;

Sätt inte parenteser för enskilt argument med kommentar på radslut (#1518)

Vår detekteringskod för när en pilfunktion ska skrivas utan parenteser kontrollerade bara om det fanns en kommentar, men vi vill bara hantera inline-kommentarer som (/* comment */ num), inte kommentarer på radslut.

// Before
KEYPAD_NUMBERS.map((num) => ( // Buttons 0-9
<div />
));

KEYPAD_NUMBERS.map(num => ( // Buttons 0-9
<div />
));

Indentera inte kapslade ternära uttryck (#1822)

Detta undviker att det ser ut som en indentering på 4 tecken istället för två. Nackdelen är att flerradiga villkor inte blir korrekt justerade, men vi anser att det är ett bättre kompromiss. Vid kapslade ternära uttryck är villkoren oftast korta.

// Before
aaaaaaaaaaaaaaa
? bbbbbbbbbbbbbbbbbb
: ccccccccccccccc
? ddddddddddddddd
: eeeeeeeeeeeeeee ? fffffffffffffff : gggggggggggggggg;

// After
aaaaaaaaaaaaaaa
? bbbbbbbbbbbbbbbbbb
: ccccccccccccccc
? ddddddddddddddd
: eeeeeeeeeeeeeee ? fffffffffffffff : gggggggggggggggg;

Infoga kedjade villkor inom JSX-attribut (#1519)

Vi behöver inte använda indentering för att disambiguera eftersom inget kan komma efter.

// Before
<div
src={
!isEnabled &&
diffUpdateMessageInput != null &&
this.state.isUpdateMessageEmpty
}
/>;

// After
<div
src={
!isEnabled &&
diffUpdateMessageInput != null &&
this.state.isUpdateMessageEmpty
}
/>;

Av-escape onödigt escapade tecken i strängar (#1575) av @josephfrazier

Vi försöker redan städa upp strängar på olika sätt - detta är ytterligare en liten förbättring som tar bort onödiga \.

// Before
a = 'hol\a';

// After
a = 'hola';

Fixa boolesk hantering för tomma objekt (#1590) av @dmitrika

Vi vill infoga objekt inom booleska uttryck eftersom det ser konstigt ut med { på egen rad. Men det leder till konstigt beteende för tomma objekt, så vi behåller dem på egen rad när de är tomma.

const x = firstItemWithAVeryLongNameThatKeepsGoing ||
secondItemWithALongNameAsWell || {};

// After
const x =
firstItemWithAVeryLongNameThatKeepsGoing ||
secondItemWithALongNameAsWell ||
{};

Ta bort parenteser från SequenceExpressions i ForStatements (#1597) av @k15a

Det är vanligt att tilldela flera värden inom en for-loop - nu lägger vi inte till onödiga parenteser.

// Before
for ((i = 0), (len = arr.length); i < len; i++) {

// After
for (i = 0, len = arr.length; i < len; i++) {

Infoga inte pilar när argument har inledande kommentar (#1660)

Om du placerar blockkommentarer inom pilfunktioner, förstör vi inte längre allt!

// Before
export const bem = block => /**
* @param {String} [element] - the BEM Element within that block; if undefined, selects the block itself.
*/
element => /**
* @param {?String} [modifier] - the BEM Modifier for the Block or Element; if undefined, selects the Block or Element unmodified.
*/
modifier =>

// After
export const bem = block =>
/**
* @param {String} [element] - the BEM Element within that block; if undefined, selects the block itself.
*/
element =>
/**
* @param {?String} [modifier] - the BEM Modifier for the Block or Element; if undefined, selects the Block or Element unmodified.
*/
modifier =>

Fixa sista kommentarer vid import (#1677)

Ytterligare ett ställe där vi behöver hantera kommentarer speciellt!

// Before
import {
ExecutionResult,
DocumentNode,
/* tslint:disable */
SelectionSetNode,
} /* tslint:enable */ from 'graphql';

// After
import {
DocumentNode,
/* tslint:disable */
SelectionSetNode,
/* tslint:enable */
} from 'graphql';

Hantera kommentarer i medlemskedjor (#1686, #1691)

Vi hanterade vissa placeringar tidigare och fortsatte lägga till fler ställen där de kan förekomma, nu byter vi till en mer generell metod. Förhoppningsvis bör dessa problem inte dyka upp igen i framtiden.

// Before
const configModel = this.baseConfigurationService.getCache().consolidated // global/default values (do NOT modify)
.merge(this.cachedWorkspaceConfig);

// After
const configModel = this.baseConfigurationService
.getCache()
.consolidated // global/default values (do NOT modify)
.merge(this.cachedWorkspaceConfig);

Använd expandLast för nästlade pilfunktioner (#1720)

// Before
f(action => next =>
next(action));

// After
f(action => next =>
next(action),
);

Placera JSX-kommentarer inom parenteser (#1712)

Detta påverkar främst Facebook-utvecklare där vi automatiskt lägger till $FlowFixMe när vi pushar en ny version av Flow. Nu förstörs inte längre dessa kommentarer.

// Before
const aDiv = /* $FlowFixMe */
(
<div className="foo">
Foo bar
</div>
);

// After
const aDiv = (
/* $FlowFixMe */
<div className="foo">
Foo bar
</div>
);

Tvinga radbrytning vid flera variabeldeklarationer (#1723)

Detta har efterfrågats ofta. Tidigare bröt vi bara vid flera variabeldeklarationer om raden var > 80 tecken. Nu gör vi det alltid om minst en deklaration har ett tilldelat värde.

// Before
var numberValue1 = 1, numberValue2 = 2;

// After
var numberValue1 = 1,
numberValue2 = 2;

Infoga | null och | void inline (#1734)

Den expanderade versionen av Flow-union ser bra ut när det gäller många objekt, men vid användning för nullbarhet ser den väldigt konstig ut. Vi infogar nu | null och | void.

// Before
interface RelayProps {
articles:
| Array<
| {
__id: string,
}
| null
>
| null
}

// After
interface RelayProps {
articles: Array<{
__id: string,
} | null> | null,
}

Bryt på implements istället för extends (#1730)

Vi bryter inte längre på extends. Detta bör göra klasser med extends som kan brytas mindre konstiga.

// Before
class MyContractSelectionWidget
extends React.Component<
void,
MyContractSelectionWidgetPropsType,
void
> {
method() {}
}

// After
class MyContractSelectionWidget extends React.Component<
void,
MyContractSelectionWidgetPropsType,
void
> {
method() {}
}

Infoga enstaka import-satser inline (#1729)

På samma sätt som vi inte bryter långa require-anrop, bryter vi inte längre import-satser om endast en sak importeras.

// Before
import somethingSuperLongsomethingSuperLong
from "somethingSuperLongsomethingSuperLongsomethingSuperLong";

// After
import somethingSuperLongsomethingSuperLong from "somethingSuperLongsomethingSuperLongsomethingSuperLong";

Lägg till förmågan för SequenceExpression att brytas (#1749)

Visste du att om ingen av dina kodrader var satser, kunde du använda () istället för {} och , istället för ;? Nu vet du det. Vissa utnyttjar detta när de returnerar saker från pilfunktioner. Det rekommenderas inte men är lätt att stödja i Prettier så varför inte ¯\_(ツ)_/¯

// Before
const f = (argument1, argument2, argument3) =>
(doSomethingWithArgument(argument1), doSomethingWithArgument(
argument2
), argument1);

// After
const f = (argument1, argument2, argument3) => (
doSomethingWithArgument(argument1),
doSomethingWithArgument(argument2),
argument1
);

Tvinga inte radbrytning i tomma loopkroppar (#1815)

Loopar med tom kropp har inte längre sina {} uppdelade på två rader.

// Before
while (true) {
}

// After
while (true) {}

Bevara tomma rader mellan switch-case med kommentarer (#1708)

// Before
switch (true) {
case true:
// Good luck getting here
case false:
}

// After
switch (true) {
case true:

// Good luck getting here
case false:
}

Korrekthet

Ta bort ast-types (#1743, #1744, #1745, #1746, #1747)

Tidigare lokaliserade vi kommentarer genom att traversera AST med hjälp av definitioner från ast-types. Ibland orsakade detta problem när vissa fält inte var deklarerade – då hittade vi inte noden och kommentarer kunde hamna fel eller orsaka felmeddelanden. Nu har vi insett att vi inte behöver hålla denna mappning utan kan enkelt traversera objekten och om en nod har ett type-fält så är det en nod.

// Before
Error: did not recognize object of type "ObjectTypeSpreadProperty"

// After
type X = {...Y/**/};
type X = {/**/...Y};

Bevara ovanliga unicode-mellanslag (#1658, #1165) av @karl och @yamafaktory

Om du lade till osynliga tecken i JSX-text ersatte vi dem tidigare med vanliga mellanslag. Vi vet inte varför någon skulle vilja göra detta, men nu skriver vi tillbaka dem exakt som de är!

Låt inte avslutande malliteral-kommentarer undkomma (#1580, #1713, #1598, #1713) av @josephfrazier och @k15a

Vi hade tidigare komplicerad (och inte fullt fungerande) kod för att hantera kommentarer i malliteraler. Nu använder vi samma eleganta lösning som för JSX-uttryck {}: vi inför en gräns precis före } och om det finns oskrivna kommentarer skriver vi ut dem alla, lägger till ett radbyte och skriver sedan }. Denna logik använder vi nu även för malliteraler :)

// Before
`${0} // comment`;

// After
`${
0
// comment
}`;

Parentesera await korrekt (#1513, #1595, #1593) av @bakkot och @existentialism

Vi har ingen automatiserad parenteshantering – istället specificerar vi alla möjliga nodkombinationer och när parenteser behövs. Det finns säkert många ovanliga kombinationer kvar att fixa. I detta fall gjorde vi await-hanteringen mer robust genom att både lägga till parenteser där de behövs och ta bort dem när de är överflödiga.

// Before
(await spellcheck) && spellcheck.setChecking(false);
new A((await x));

// After
await (spellcheck && spellcheck.setChecking(false));
new A(await x);

Bevara getter/setter-information i flow-ObjectTypeProperty (#1585) av @josephfrazier

Ännu ett specialfall som vi inte helt fått rätt på!

// Before
type T = { method: () => void };

// After
type T = { get method(): void }

Lägg till parenteser för enstaka argumenttyper med generics (#1814)

Ytterligare ett fall av smygande parenteser som vi inte hanterade korrekt!

// Before
type ExtractType = <A>B<C> => D

// After
type ExtractType = <A>(B<C>) => D

Fall tillbaka på icke-strikt läge i babylon (#1587, #1608) av @josephfrazier

Vi vill att Prettier ska kunna parsa all JavaScript-kod. För babylon-parsern måste vi välja om en fil använder strikt läge eller inte. Vi valde strikt läge som standard eftersom de flesta filer fungerar så. Men om du har oktala literaler som 0775 kunde det inte parsas. Nu försöker vi först i strikt läge, och om det misslyckas försöker vi i icke-strikt läge. Vi tillåter också return utanför funktioner eftersom det är giltigt i node-filer.

// Before
SyntaxError

// After
return 0775;

CLI

Tillåt --write att användas med --list-different (#1633)

Detta är användbart att kombinera båda om du skapar en commit-hook för att visa användaren vad som faktiskt ändrades i ett enda kommando.

Ignorera node_modules när du kör prettier via CLI (#1683) av @thymikee

Det är väldigt lätt att av misstag köra prettier på node_modules/-mappen, vilket du nästan aldrig vill göra. Nu inaktiverar vi det som standard och lägger till ett --with-node-modules-alternativ om du verkligen vill.

Genomsök punktfiler med glob (#1844) av @jhgg

Vi aktiverade alternativet att inkludera .dotfiles i glob-biblioteket vi använder. Det innebär att * nu matchar filer som .eslintrc.