Saltar al contenido principal

Prettier 1.6: Archivo de configuración, JSX

· 16 min de lectura
Traducción Beta No Oficial

Esta página fue traducida por PageTurner AI (beta). No está respaldada oficialmente por el proyecto. ¿Encontraste un error? Reportar problema →

Esta versión añade soporte para archivos de configuración en Prettier, así como mejoras significativas en el formato de JSX.

Quiero agradecer especialmente a @azz quien ha mantenido el repositorio e implementado muchos de los cambios en esta versión, ya que tuve menos tiempo para dedicar a prettier debido a vacaciones y cambio de equipo :)

Destacados

Configuración

Implementación de cosmiconfig para configuración de espacios de trabajo (#2434) por @azz

Desde el primer lanzamiento de prettier, los usuarios han solicitado un archivo .prettierrc. Intentábamos tener la menor cantidad de opciones posible y evitar ser un .dotfile más que debes tener al iniciar un nuevo proyecto.

Pero la realidad es que necesitábamos una forma de configurar prettier que se mantuviera sincronizada con todas las integraciones. Al no tenerla, trasladamos el problema a ellas y vimos múltiples enfoques incompatibles para manejarlo. Ahora, esto lo gestiona prettier directamente.

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

Para más información sobre el soporte de archivos de configuración, consulta el README.

Soporte para archivos .prettierignore (#2412) por @evilebottnawi

Además de especificar qué configuración usar, puedes crear un archivo .prettierignore para indicar qué archivos no formatear.

## .prettierignore
dist/
package.json

JSX

Mejoras en el formato de JSX (#2398) por @suchipi

El último gran punto de fricción para quienes adoptaban prettier era cómo se formateaba el JSX. Revisamos todos los problemas reportados e implementamos varios cambios:

  • Las expresiones de función flecha que devuelven JSX ahora añaden paréntesis cuando el JSX se divide en múltiples líneas
// Before
const Component = props =>
<div>
Hello {props.name}!
</div>;

// After
const Component = props => (
<div>
Hello {props.name}!
</div>
);
  • Las expresiones condicionales dentro de (o que contienen) JSX se formatean usando paréntesis de manera diferente
// Before
<div>
{props.isVisible
? <BaseForm
url="/auth/google"
method="GET"
/>
: <Placeholder />}
</div>;

// After
<div>
{props.isVisible ? (
<BaseForm
url="/auth/google"
method="GET"
/>
) : (
<Placeholder />
)}
</div>
  • El JSX en expresiones lógicas (|| o &&) siempre se envuelve en paréntesis cuando el JSX se divide en múltiples líneas
// Before
<div>
{props.isVisible &&
<BaseForm
url="/auth/google"
method="GET"
/>}
</div>;

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

Esperamos que esto se alinee mejor con cómo escribe JSX la mayoría de la comunidad y que podamos usar prettier en más lugares ;)

Expresiones únicas en línea en JSX (#2442) por @karl

Con JSX, inicialmente respetábamos muchos saltos de línea del código fuente original. Esto tenía la ventaja de realizar menos cambios en tu base de código, pero reducía el valor de un formateador consistente ya que el mismo código semántico podía escribirse de dos formas distintas.

En cada nueva versión hemos ajustado esto y tomado decisiones sobre cómo imprimir siempre un fragmento de código. La más reciente es que si hay un único hijo en un objeto JSX, ahora siempre lo pondremos en línea.

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

Asegurar un salto de línea después de espacios en blanco iniciales en JSX (#2348) por @karl

Los espacios vacíos iniciales en JSX ahora aparecen en su propia línea. Se veía extraño tenerlos antes de una etiqueta ya que la "sangraban" de manera diferente al resto.

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

Otros cambios

JSON

Usar babylon.parseExpression para JSON (#2476) por @josephfrazier

Antes usábamos un analizador JSON estricto que fallaba si había comentarios o comas finales. Esto resultaba inconveniente porque muchos archivos JSON en la práctica se analizan con JavaScript o json5, que son menos estrictos. Ahora hemos relajado esto y usamos el analizador de JavaScript para procesar e imprimir JSON. Esto significa que los comentarios se mantendrán si existían.

Nota: esto es puramente aditivo. Si tu archivo original cumplía con JSON, seguirá imprimiendo un JSON válido.

// Before
Syntax error

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

JavaScript

Imprimir 3 o más llamadas encadenadas en múltiples líneas (#2673) por @azz

Este era un problema persistente con nuestra forma de imprimir largas cadenas de miembros. Prettier intentaba comprimir todo excepto la última devolución de llamada en una sola línea, lo que reducía la legibilidad. La solución que adoptamos fue dividir siempre en múltiples líneas cuando hay tres o más llamadas a funciones en una cadena de métodos.

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

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

Añadir más paréntesis de supervisión (#2423) por @azz

Los paréntesis son un tema delicado porque no forman parte del AST, así que Prettier ignora todos los que añades y los recrea desde cero. Revisamos todos los casos reportados y encontramos varios casos límite que resultaban confusos cuando se encadenaban comparaciones y se mezclaba % con * o /.

Algo que no cambiamos es que seguimos eliminando paréntesis extra alrededor de combinaciones de operadores aritméticos básicos: +-*/.

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

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

Implementar prettier-ignore dentro de JSX (#2487) por @azz

Es útil poder ignorar fragmentos de JSX. Ahora es posible añadir un comentario dentro de una expresión JSX para ignorar el formato del siguiente elemento.

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

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

No omitir comentarios prettier-ignore (#2664)

Internamente tenemos mecanismos para evitar imprimir comentarios genéricamente y mostrarlos en otro lugar. Resulta que cuando usábamos prettier-ignore, ¡no imprimíamos los comentarios en absoluto! Esto ya está corregido.

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

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

Corregir la sangría de condiciones en do-while (#2359) por @jsnajdr

Pasaron 6 meses hasta que alguien reportó que los bucles do-while fallaban cuando la condición while ocupaba múltiples líneas, lo que confirma mi sospecha de que esta estructura no se usa ampliamente en la práctica.

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

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

Dividir expresiones de secuencia (#2388) por @bakkot

Otra característica poco utilizada de JavaScript son las expresiones de secuencia. Hacíamos un mal trabajo al imprimirlas cuando ocupaban múltiples líneas, pero esto ya está corregido :)

// 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')

Eliminar espacios en blanco finales en comentarios (#2494) por @azz

En Prettier adoptamos la postura de eliminar todos los espacios en blanco finales. Solíamos no tocar los comentarios por ser contenido generado por el usuario, ¡pero eso no significa que deban tener espacios innecesarios :)

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

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

Corregir comentarios intercalados en decoradores de clases (#2660, #2661)

Nuestro manejo de comentarios dentro de declaraciones de clases era muy básico: simplemente movíamos todos los comentarios hacia la parte superior. Ahora somos más precisos y respetamos los comentarios intercalados entre decoradores y alrededor de extends.

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

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

Mejora en el formato de expresiones bind (#2493) por @azz

Las expresiones bind están siendo discutidas en TC39 y consideramos que podríamos formatearlas con Prettier. Antes teníamos un enfoque muy básico que simplemente las encadenaba. Ahora aplicamos la misma lógica que usamos para el encadenamiento de métodos con el operador .. También corregimos algunos casos extremos donde producía código inválido.

// 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);

Añadir soporte para el enlace opcional en bloques catch (#2570) por @existentialism

Actualmente se discute en TC39 la posibilidad de hacer opcional el argumento en catch(e). Asegurémonos de soportarlo en Prettier si los desarrolladores lo usan.

// Before
Syntax error

// After
try {} catch {}

Añadir soporte para la sintaxis de encadenamiento opcional (#2572) por @azz

Otra nueva propuesta discutida en TC39 es la sintaxis de encadenamiento opcional. Actualmente es una propuesta en etapa 1, por lo que la sintaxis podría cambiar en cualquier momento.

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

Manejar correctamente la sintaxis de conversión de tipos de Closure Compiler (#2484) por @yangsu

Los comentarios son difíciles de manejar correctamente, especialmente cuando su significado depende de su posición. Ahora manejamos de forma especial los comentarios usados como conversión de tipos para Closure Compiler, manteniendo su semántica original.

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

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

Integrar la primera búsqueda de propiedad computada en cadenas de miembros (#2670) por @azz

Resultaba extraño tener una búsqueda de propiedad computada en una línea separada, así que añadimos un caso especial para integrarla.

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

Soporte para tipos opacos y exportación en estrella (#2543, #2542) por @existentialism

El equipo de Flow introdujo dos características muy interesantes con nueva sintaxis. Ahora las soportamos en Prettier. Personalmente llevaba muchísimo tiempo esperando los tipos opacos.

// Before
Syntax error

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

Eliminar comillas innecesarias en claves de objetos de tipo e interfaces (#2643) por @jackyho112

Hacemos esto en objetos JavaScript desde los primeros días de Prettier, pero olvidamos aplicar lo mismo a tipos de Flow y TypeScript.

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

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

Imprimir TypeParameter incluso en tipos de función unarios (#2406) por @danwang

¡Ups! Estábamos omitiendo el genérico en este caso específico.

// Before
type myFunction = A => B;

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

Mantener paréntesis alrededor de FunctionTypeAnnotation dentro de ArrayTypeAnnotation (#2561) por @azz

Paréntesis... algún día arreglaremos todos :)

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

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

TypeScript

Compatibilidad con TypeScript 2.5 RC (#2672) por @azz

TypeScript 2.5 RC se anunció recientemente, permitiéndote usar también la nueva sintaxis de "enlace opcional en catch" en TypeScript. 🎉

No agregar namespace keyword a declaraciones globales (#2329) por @azz

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

// After
global {
export namespace JSX {}
}

Corregir <this.Component /> (#2472) por @backus

Gracias a la naturaleza no tipada y permisiva de JavaScript, pudimos concatenar undefined a un string y obtener código interesante. Ahora corregido para este caso :)

// Before
<undefined.Author />

// After
<this.Author />

Permitir que las aserciones de tipo se mantengan compactas (#2439) por @azz

Queremos asegurar que todos los casos especiales que añadimos para JavaScript y Flow también funcionen para construcciones de TypeScript. En este caso, los objetos también deben compactarse si están envueltos en un operador 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);

Eliminar paréntesis para aserciones de tipo en expresiones binarias (#2419) por @azz

Normalmente añadimos paréntesis por corrección, pero en este caso los agregábamos innecesariamente, así que podemos eliminarlos para obtener un código más limpio :)

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

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

Imprimir paréntesis alrededor de aserciones de tipo como LHS en asignaciones (#2525) por @azz

Otro caso más de paréntesis faltantes. Afortunadamente, hoy en día son muy escasos y corresponden a casos extremadamente raros.

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

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

Imprimir declare para TSInterfaceDeclaration (#2574) por @existentialism

La palabra clave declare no tiene efecto en interface, así que nunca la incluíamos. Sin embargo, resultaba extraño ver en archivos de declaración que todo tuviera declare excepto las interfaces. Ahora reimprimimos declare si estaba presente originalmente.

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

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

CSS

Normalizar comillas en CSS (#2624) por @lydell

Para lanzar una primera versión de CSS, mantuvimos las comillas de strings como estaban. Ahora respetamos la opción singleQuote de Prettier. La dificultad fue asegurar código correcto para escapes complejos, caracteres Unicode, emojis, y reglas especiales como charset que solo funcionan con comillas dobles...

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

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

Normalizar números en CSS (#2627) por @lydell

Otro caso donde podemos reutilizar la lógica implementada para JavaScript para mejorar el formato CSS.

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

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

Entrecomillar valores de atributos CSS sin comillas en selectores (#2644) por @lydell

Nunca recuerdo bien las reglas sobre comillas en atributos, así que ahora siempre las añadimos.

// Before
a[id=test] {}

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

Añadir compatibilidad con la palabra clave css (#2337) por @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;
}
`;

Soporte para styled-components con componentes existentes (#2552, #2619) por @azz

styled-components tiene muchas variantes para etiquetar literales de plantilla como CSS. No es ideal que tengamos que codificar todas esas formas dentro de Prettier, pero ya que empezamos, mejor hacerlo bien.

styled(ExistingComponent)`
css: property;
`;

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

Eliminar espacios en blanco en el combinador de descendientes (#2411) por @azz

Los analizadores sintácticos de CSS que usamos no nos dan un árbol 100% semántico: en muchas ocasiones fallan y simplemente devuelven lo que se ingresó. Depende de nosotros asegurarnos de limpiar esto manteniendo la corrección. En este caso, imprimíamos los espacios entre selectores tal cual, pero sabemos que es correcto reemplazarlos siempre por un solo espacio.

// Before
.hello

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

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

Eliminar BOM antes del análisis (#2373) por @azz

Todavía tengo pesadillas al lidiar con BOM en una vida anterior. Afortunadamente, en 2017 ya no es un gran problema ya que la mayoría de las herramientas lo reconocen. Gracias @azz por corregir casos extremos relacionados con el análisis de CSS.

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

GraphQL

Añadir soporte para formato de rango en GraphQL (#2319) por @josephfrazier

Si intentabas usar la función de formato de rango en un archivo GraphQL, lanzaba una excepción; ahora vuelve a funcionar correctamente y solo reformatea la parte seleccionada.

Añadir extensión .gql para análisis como GraphQL (#2357) por @rrdelaney

En Facebook usamos la extensión .graphql, pero parece común también tener .gql. No cuesta mucho soportarlo en la heurística que decide qué analizador usar.

CLI

Soporte para múltiples patrones con patrón de ignorado (#2356) por @evilebottnawi

Ya era posible tener múltiples patrones glob, pero eran aditivos; con este cambio, puedes añadir un patrón glob para ignorar ciertos archivos. Debería ser muy útil para ignorar carpetas profundamente anidadas.

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

Hacer que --list-different funcione con --stdin (#2393) por @josephfrazier

Esta es una forma práctica de saber si Prettier imprimiría un fragmento de código de manera diferente. Ya teníamos todos los conceptos implementados, solo necesitábamos conectarlos correctamente.

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