Prettier 1.4: Soporte para TypeScript y CSS
Esta página fue traducida por PageTurner AI (beta). No está respaldada oficialmente por el proyecto. ¿Encontraste un error? Reportar problema →
¡Esta versión introduce soporte para TypeScript, CSS, Less y SCSS en Prettier!
Soporte para TypeScript
Esta es la función más solicitada para Prettier. Con la versión 1.4.0, ¡ahora puedes usar Prettier para formatear tus archivos .ts y .tsx!
Prettier funciona utilizando proyectos para generar una representación AST del código e imprimirlo. Tanto Babylon (el parser que impulsa Babel) como Flow producen un AST que sigue aproximadamente el formato estree para las partes de JavaScript, además de nodos especiales para las características específicas de Flow.
TypeScript, al igual que Flow, introduce nodos especiales para su sintaxis específica. Desafortunadamente, no sigue el formato estree para el resto del lenguaje JavaScript. Esto nos coloca en una situación complicada con Prettier, ya que tendríamos que bifurcarlo completamente para poder imprimir TypeScript.
Esta incompatibilidad con el AST no es un problema nuevo. Otro proyecto que luchó con esto fue ESLint. Debido a que el AST es diferente, ninguna de las reglas de ESLint funciona. Afortunadamente, @JamesHenry y @soda0289 crearon un proyecto llamado typescript-eslint-parser que toma un AST de TypeScript y lo convierte a estree, ¡exactamente lo que necesitamos para Prettier!
Tras integrar ese proyecto en Prettier, @azz, @despairblue y @Pajn implementaron todos los nodos específicos de TypeScript y aseguraron que las 13k pruebas de la suite de TypeScript pasen correctamente. Fue un esfuerzo enorme que finalmente está listo para usarse :)
Probamos Prettier en los proyectos de TypeScript más grandes que encontramos en GitHub para garantizar que imprime código correcto. Aún no hemos dedicado mucho tiempo a optimizar el formato del código, así que si ves algo extraño, ¡por favor crea un issue!
Soporte para CSS, Less y SCSS
Mientras TypeScript es la función más solicitada en open source, CSS es la más demandada por ingenieros de Facebook. ¡Una vez que te acostumbras a formatear código en un lenguaje, quieres hacerlo en todos!
Resulta que CSS es un lenguaje mucho más pequeño que JavaScript y su soporte solo tomó unos días. Usamos postcss de @ai como parser base, capaz de procesar CSS, Less y SCSS. También dependemos de postcss-values-parser, postcss-selector-parser de @ben-eb y postcss-media-query-parser de @dryoma.
Lamentablemente, postcss actualmente no soporta Sass ni Stylus. Estaríamos encantados de añadirlos si alguien se ofrece a implementar su impresión.
Nota: Prettier actualmente solo formatea el código, aún no respeta opciones como singleQuote ni realiza normalización de colores o números como hacemos para JavaScript.
Integración con editores
La primera fase del proyecto fue hacer que Prettier generara código correcto y bien formateado. Ahora que está en buen estado, podemos dedicar tiempo a mejorar las integraciones. Acabamos de añadir soporte para dos grandes características: mantener la posición del cursor y formatear rangos específicos en lugar de archivos completos.
Ten en cuenta que acabamos de integrar esta funcionalidad en Prettier, pero aún no está siendo utilizada por ninguna de las integraciones de editores. Además, no las hemos probado exhaustivamente en la práctica, así que probablemente necesitaremos pulir algunos detalles.
Agregar opción cursorOffset para reposicionamiento del cursor (#1637) por @josephfrazier
Actualmente, dejamos que los editores determinen la posición del cursor, lo cual hacen de forma aceptable. Pero como estamos imprimiendo el código, ¡podemos proporcionar la posición exacta!
Agregar opciones --range-start/end para formatear solo partes del input (#1609) por @josephfrazier
Esta es una funcionalidad muy solicitada. Actualmente Prettier solo formatea archivos completos. Ahora es posible formatear un rango específico.
Funciona recorriendo el AST hacia arriba para encontrar la sentencia más cercana. Así no necesitas seleccionar exactamente el rango válido. ¡Puedes arrastrar aproximadamente sobre el código que quieres reformatear y funcionará!
Agregar opción filepath para inferencia de tipo de archivo (#1835) por @mitermayer
Como ahora formateamos CSS y TypeScript, no es práctico especificar el parser para cada archivo. Ahora puedes pasar la ruta del archivo y Prettier detectará la extensión para usar el parser adecuado.
Destacados
Ajuste de contenido textual en JSX (#1120, #1671, #1827, #1829) por @karl
El principal problema pendiente con Prettier en JSX era el manejo de texto. Antes insertaba un antiestético {" "} y dejaba líneas largas sin modificar. Ahora tratamos cada palabra como token y las distribuimos correctamente.
Un trabajo excepcional de @karl, quien no solo implementó la funcionalidad sino que introdujo una nueva primitiva en Prettier para imprimir secuencias de elementos y romper líneas al alcanzar el límite.
// 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>
Eliminar paréntesis en JSX dentro de funciones flecha (#1733) por @xixixao
Quienes escriben componentes funcionales celebrarán este cambio. Ya no agregamos paréntesis en funciones flecha que retornan 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>;
Mejoras en impresión de literales de plantilla (#1664, #1714) por @josephfrazier
Los literales de plantilla siempre fueron complejos para Prettier. En la versión 1.3.0 mejoramos sustancialmente su manejo, y en esta edición creemos haber resuelto adecuadamente los casos comunes.
Para resolver problemas anteriores, añadimos una utilidad que eliminaba líneas vacías, pero a veces producía resultados extraños; ya está eliminada. Otro ajuste: en lugar de indentar donde comienza ${, ahora indentamos desde el inicio de la línea que contiene ${.
¡Háganos saber si aún tienen problemas con la salida de las plantillas literales después de este lanzamiento!
// 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;
`
Usar las mismas reglas de ruptura para asignaciones y valores de objetos (#1721)
Contamos con una lógica muy afinada sobre cómo romper elementos después de asignaciones (ej. a = ...). Ahora aplicamos la misma lógica para valores de objetos. Esto debería ayudar con lógica booleana multilínea o condicionales extensos. También es un buen ejemplo de cómo podemos crear un impresor consistente.
// Before
const o = {
somethingThatsAReallyLongPropName: this.props.cardType ===
AwesomizerCardEnum.SEEFIRST,
};
// After
const o = {
somethingThatsAReallyLongPropName:
this.props.cardType === AwesomizerCardEnum.SEEFIRST,
};
Indentar condiciones dentro de !() (#1731)
Hubo un flujo constante de quejas sobre cómo se representaba anteriormente, y estaba en la lista de "probablemente difícil de implementar, revisar después". ¡Resultó ser súper sencillo, así que aquí está!
// Before
const anyTestFailures = !(aggregatedResults.numFailedTests === 0 &&
aggregatedResults.numRuntimeErrorTestSuites === 0);
// After
const anyTestFailures = !(
aggregatedResults.numFailedTests === 0 &&
aggregatedResults.numRuntimeErrorTestSuites === 0
);
Correcciones de Formato
Colocar cuerpos de bucles en la misma línea cuando sea posible (#1498)
Ya lo hacíamos para sentencias if; debemos ser consistentes y aplicarlo también para bucles.
// Before
for (a in b)
var c = {};
// After
for (a in b) var c = {};
Corregir línea vacía con unión flow (#1511) por @existentialism
No deberíamos indentar cosas dos veces ;)
// 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 }
>;
No agregar paréntesis para argumento único con comentario al final de línea (#1518)
El código de detección para funciones flecha sin paréntesis solo verificaba si había comentarios, pero solo queremos comentarios en línea como (/* comment */ num), no comentarios al final de línea.
// Before
KEYPAD_NUMBERS.map((num) => ( // Buttons 0-9
<div />
));
KEYPAD_NUMBERS.map(num => ( // Buttons 0-9
<div />
));
No indentar ternarios anidados (#1822)
Esto evita que parezca indentado por 4 caracteres en lugar de dos. La desventaja es que si la condición es multilínea no estará perfectamente alineada, pero consideramos mejor este equilibrio. Si usas ternarios anidados, normalmente tienes condiciones pequeñas.
// Before
aaaaaaaaaaaaaaa
? bbbbbbbbbbbbbbbbbb
: ccccccccccccccc
? ddddddddddddddd
: eeeeeeeeeeeeeee ? fffffffffffffff : gggggggggggggggg;
// After
aaaaaaaaaaaaaaa
? bbbbbbbbbbbbbbbbbb
: ccccccccccccccc
? ddddddddddddddd
: eeeeeeeeeeeeeee ? fffffffffffffff : gggggggggggggggg;
Condicionales encadenados en línea dentro de atributos JSX (#1519)
No necesitamos usar indentación para desambiguar otro bloque ya que nada puede venir después.
// Before
<div
src={
!isEnabled &&
diffUpdateMessageInput != null &&
this.state.isUpdateMessageEmpty
}
/>;
// After
<div
src={
!isEnabled &&
diffUpdateMessageInput != null &&
this.state.isUpdateMessageEmpty
}
/>;
Eliminar caracteres innecesariamente escapados en strings (#1575) por @josephfrazier
Ya intentamos limpiar strings de varias formas; esta es otra pequeña adición que eliminará \ innecesarios.
// Before
a = 'hol\a';
// After
a = 'hola';
Corregir booleano para objetos vacíos (#1590) por @dmitrika
Queríamos poner objetos en línea dentro de expresiones booleanas porque se ve raro tener { en su propia línea. Pero resulta que causa comportamientos extraños con objetos vacíos. Así que los mantenemos en su propia línea si están vacíos.
const x = firstItemWithAVeryLongNameThatKeepsGoing ||
secondItemWithALongNameAsWell || {};
// After
const x =
firstItemWithAVeryLongNameThatKeepsGoing ||
secondItemWithALongNameAsWell ||
{};
Eliminar paréntesis de SequenceExpressions en ForStatements (#1597) por @k15a
Es común asignar múltiples valores dentro de un bucle for; ahora ya no agregamos paréntesis.
// Before
for ((i = 0), (len = arr.length); i < len; i++) {
// After
for (i = 0, len = arr.length; i < len; i++) {
No poner en línea funciones flecha cuando el argumento tiene comentario inicial (#1660)
¡Si colocas comentarios en bloque dentro de funciones flecha, ya no arruinamos todo!
// 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 =>
Corregir últimos comentarios en imports (#1677)
¡Otro caso donde necesitamos lógica especial para los comentarios!
// Before
import {
ExecutionResult,
DocumentNode,
/* tslint:disable */
SelectionSetNode,
} /* tslint:enable */ from 'graphql';
// After
import {
DocumentNode,
/* tslint:disable */
SelectionSetNode,
/* tslint:enable */
} from 'graphql';
Manejar comentarios en cadenas de miembros (#1686, #1691)
Antes manejábamos algunas ubicaciones y seguíamos añadiendo casos donde podían aparecer. Ahora adoptamos un enfoque más general. Esperamos que estos problemas no vuelvan a surgir.
// 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);
Usar expandLast para funciones flecha anidadas (#1720)
// Before
f(action => next =>
next(action));
// After
f(action => next =>
next(action),
);
Colocar comentarios JSX dentro de los paréntesis (#1712)
Esto afecta principalmente a ingenieros de Facebook donde añadimos automáticamente $FlowFixMe al actualizar Flow. Ahora no desordena esos comentarios.
// Before
const aDiv = /* $FlowFixMe */
(
<div className="foo">
Foo bar
</div>
);
// After
const aDiv = (
/* $FlowFixMe */
<div className="foo">
Foo bar
</div>
);
Forzar \n en declaraciones múltiples de variables (#1723)
Muy solicitado. Antes solo rompíamos declaraciones múltiples si superaban 80 columnas. Ahora lo hacemos siempre que haya al menos una con asignación.
// Before
var numberValue1 = 1, numberValue2 = 2;
// After
var numberValue1 = 1,
numberValue2 = 2;
Incluir | null y | void en línea (#1734)
La versión expandida de uniones Flow funciona bien con objetos, pero para nulabilidad se ve raro. Ahora ponemos en línea | null y | void.
// Before
interface RelayProps {
articles:
| Array<
| {
__id: string,
}
| null
>
| null
}
// After
interface RelayProps {
articles: Array<{
__id: string,
} | null> | null,
}
Romper en implements en lugar de extends (#1730)
Ya no rompemos en extends. Mejora la apariencia de clases con extends que podían romperse.
// Before
class MyContractSelectionWidget
extends React.Component<
void,
MyContractSelectionWidgetPropsType,
void
> {
method() {}
}
// After
class MyContractSelectionWidget extends React.Component<
void,
MyContractSelectionWidgetPropsType,
void
> {
method() {}
}
Import único en línea (#1729)
Igual que no rompemos require largos, ahora no rompemos import si solo se importa un elemento.
// Before
import somethingSuperLongsomethingSuperLong
from "somethingSuperLongsomethingSuperLongsomethingSuperLong";
// After
import somethingSuperLongsomethingSuperLong from "somethingSuperLongsomethingSuperLongsomethingSuperLong";
Permitir que SequenceExpression pueda romperse (#1749)
¿Sabías que sin declaraciones podrías usar () en vez de {} y , en vez de ;? Algunos usan esto al retornar en funciones flecha. No es recomendable, pero es fácil de soportar en Prettier ¯\_(ツ)_/¯
// Before
const f = (argument1, argument2, argument3) =>
(doSomethingWithArgument(argument1), doSomethingWithArgument(
argument2
), argument1);
// After
const f = (argument1, argument2, argument3) => (
doSomethingWithArgument(argument1),
doSomethingWithArgument(argument2),
argument1
);
No forzar salto de línea en cuerpos vacíos de bucles (#1815)
Bucles con cuerpo vacío ya no dividen sus {} en dos líneas.
// Before
while (true) {
}
// After
while (true) {}
Conservar líneas vacías entre casos de switch con comentarios (#1708)
// Before
switch (true) {
case true:
// Good luck getting here
case false:
}
// After
switch (true) {
case true:
// Good luck getting here
case false:
}
Corrección
Eliminar ast-types (#1743, #1744, #1745, #1746, #1747)
Solíamos ubicar comentarios recorriendo el AST usando definiciones de ast-types. Esto ocasionalmente causaba problemas cuando algún campo no estaba declarado: no encontrábamos el nodo y los comentarios se imprimían en ubicaciones incorrectas o generaban errores. Resulta que no necesitamos mantener este mapeo; podemos simplemente recorrer los objetos y, si un nodo tiene un campo type, entonces es un nodo válido.
// Before
Error: did not recognize object of type "ObjectTypeSpreadProperty"
// After
type X = {...Y/**/};
type X = {/**/...Y};
Preservar espacios Unicode inusuales (#1658, #1165) por @karl y @yamafaktory
Si añadías caracteres invisibles dentro de texto JSX, los reemplazábamos por espacios normales. ¡No sabemos por qué alguien querría hacer eso, pero ahora los imprimimos tal cual!
Evitar que comentarios finales en literales de plantilla escapen (#1580, #1713, #1598, #1713) por @josephfrazier y @k15a
Teníamos código complejo (y poco efectivo) para manejar comentarios dentro de literales de plantilla. Implementamos una solución elegante para expresiones JSX {}: creamos un límite antes del } final y, si quedan comentarios sin imprimir, los volcamos todos, añadimos un \n e imprimimos el }. ¡Ahora aplicamos esta lógica a los literales de plantilla! :)
// Before
`${0} // comment`;
// After
`${
0
// comment
}`;
Parentizar await correctamente (#1513, #1595, #1593) por @bakkot y @existentialism
No automatizamos la inserción de paréntesis; en su lugar, especificamos todas las combinaciones posibles de nodos y cuándo requieren paréntesis. Es probable que aún queden casos excepcionales. En esta ocasión, mejoramos sustancialmente el manejo de await añadiendo paréntesis donde son necesarios y eliminándolos cuando no lo son.
// Before
(await spellcheck) && spellcheck.setChecking(false);
new A((await x));
// After
await (spellcheck && spellcheck.setChecking(false));
new A(await x);
Preservar información de getters/setters en ObjectTypeProperty de Flow (#1585) por @josephfrazier
¡Otro caso excepcional que aún no habíamos resuelto!
// Before
type T = { method: () => void };
// After
type T = { get method(): void }
Añadir paréntesis para tipos de argumento único con genéricos (#1814)
¡Otro caso de paréntesis furtivos que omitíamos!
// Before
type ExtractType = <A>B<C> => D
// After
type ExtractType = <A>(B<C>) => D
Recurrir al modo no estricto en Babylon (#1587, #1608) por @josephfrazier
Queremos que Prettier pueda analizar todo el JavaScript existente. En Babylon debemos elegir si un archivo usa modo estricto. Optamos por modo estricto por defecto, ya que la mayoría de archivos se analizan así. Pero con literales octales como 0775, ni siquiera se analizaba. Ahora, si falla en modo estricto, intentamos en modo no estricto. También permitimos return fuera de funciones, válido en archivos Node.
// Before
SyntaxError
// After
return 0775;
CLI
Permitir usar --write con --list-different (#1633)
Es útil combinar ambas opciones si estás creando un commit hook para mostrar al usuario qué cambió exactamente en un solo comando.
Ignorar node_modules al ejecutar prettier desde CLI (#1683) por @thymikee
Es muy fácil ejecutar prettier accidentalmente sobre la carpeta node_modules/, algo que casi nunca se desea. Ahora lo desactivamos por defecto y añadimos la opción --with-node-modules si realmente se necesita.
Recorrer archivos ocultos en glob (#1844) por @jhgg
Habilitamos la opción para procesar archivos ocultos (dotfiles) en la librería de análisis de glob que usamos. Esto significa que al escribir * ahora se incluirán archivos como .eslintrc.

