Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -728,8 +728,15 @@ AST visitors: `JSXAttribute`, `CallExpression`, `TaggedTemplateExpression`, `Var
object value — and write the same block between the quotes: a JSX string may span lines as
written, a JS string can't. Its value keeps the file's `\r\n` (a template's is LF), so it is
measured and wrapped in LF and written back with the file's line ending (`lineEndingOf`).
`multiline-preservation.test.ts` runs every fixer over both shapes; oxfmt's `sortTailwindcss`
collapses the block unless `preserveWhitespace: true` (`oxfmt-interop.test.ts`).
`wrapStrings: 'all'` adds JS strings, turned into a template literal as better-tailwindcss does:
the fix replaces the whole `Literal` (`node.range`, quotes included) with backticks around the
block, which is why `meta.fixable` is `'code'`. `isConvertibleJsString` takes only a string whose
parent accepts any expression (a call argument, `JSXExpressionContainer`, array element, object
VALUE, ternary branch, `&&`/`||` operand, variable init) — never an object key or a `+` operand —
and whose source between the quotes equals its value and holds no `` ` `` or `${`, so a template
reads it the same. `multiline-preservation.test.ts` runs every fixer over both shapes (a converted
string IS a template afterwards); oxfmt's `sortTailwindcss` collapses either block, a helper's
template included, unless `preserveWhitespace: true` (`oxfmt-interop.test.ts`).
- **Worker services lifecycle**: `sort-service.ts`, `canonicalize-service.ts` and
`declaration-service.ts` are thin wrappers around `DesignSystemWorker<Req, Res>` (in
`design-system/ds-worker.ts`). The class owns the SharedArrayBuffer + Atomics protocol and the
Expand Down
4 changes: 2 additions & 2 deletions packages/docs/data/better-tailwindcss.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@
"ours": "enforce-consistent-line-wrapping",
"example": "<div className=\"flex items-center justify-between gap-4 rounded-lg border bg-background p-6 text-sm shadow-sm\">x</div>",
"notes": {
"en": "`printWidth`, `classesPerLine` and `group` mean the same. The autofix rewrites template literals, and a JSX string attribute only with `wrapStrings: \"jsx\"` (otherwise it is reported, not rewritten); a line over `printWidth` is rewrapped only with `wrapLines`. `indent`, `tabWidth`, `lineBreakStyle`, `preferSingleLine`, `strictness` and `vueConvertToBinding` have no equivalent: the indentation and line endings come from the source.",
"es": "`printWidth`, `classesPerLine` y `group` significan lo mismo. El autofix reescribe template literals, y un atributo string de JSX solo con `wrapStrings: \"jsx\"` (si no, se reporta y no se reescribe); una línea que pasa el `printWidth` se vuelve a envolver solo con `wrapLines`. `indent`, `tabWidth`, `lineBreakStyle`, `preferSingleLine`, `strictness` y `vueConvertToBinding` no tienen equivalente: la indentación y los finales de línea salen del código."
"en": "`printWidth`, `classesPerLine` and `group` mean the same. The autofix rewrites template literals; with `wrapStrings: \"all\"` it wraps strings the way theirs does, a JSX string attribute in place and a JS string turned into a template literal (`\"jsx\"` wraps only the former, and otherwise a string is reported, not rewritten). A line over `printWidth` is rewrapped only with `wrapLines`. `indent`, `tabWidth`, `lineBreakStyle`, `preferSingleLine`, `strictness` and `vueConvertToBinding` have no equivalent: the indentation and line endings come from the source.",
"es": "`printWidth`, `classesPerLine` y `group` significan lo mismo. El autofix reescribe template literals; con `wrapStrings: \"all\"` envuelve los strings como lo hace la suya, un atributo string de JSX en su lugar y un string de JS convertido en template literal (`\"jsx\"` envuelve solo lo primero, y si no, el string se reporta y no se reescribe). Una línea que pasa el `printWidth` se vuelve a envolver solo con `wrapLines`. `indent`, `tabWidth`, `lineBreakStyle`, `preferSingleLine`, `strictness` y `vueConvertToBinding` no tienen equivalente: la indentación y los finales de línea salen del código."
}
},
{
Expand Down
9 changes: 5 additions & 4 deletions packages/docs/es/interop.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,11 @@ El formateador además elimina clases duplicadas y colapsa espacios en los strin
que ahí se solapa con `no-duplicate-classes` y `no-unnecessary-whitespace`; las reglas de lint
siguen cubriendo todo lo demás.

Eso incluye los saltos de línea de un atributo de clases que `enforce-consistent-line-wrapping`
envolvió en un bloque (`wrapStrings: "jsx"`): el formateador lo vuelve a dejar en una línea, y cada
uno deshace lo del otro. Pon `preserveWhitespace: true` en `sortTailwindcss` para conservar el
bloque.
Eso incluye los saltos de línea de un string de clases que `enforce-consistent-line-wrapping`
envolvió en un bloque, ya sea un atributo de clases (`wrapStrings: "jsx"`) o un template en un
helper que el formateador ordena (`cn(…)` con `wrapStrings: "all"`): el formateador lo vuelve a
dejar en una línea, y cada uno deshace lo del otro. Pon `preserveWhitespace: true` en
`sortTailwindcss` para conservar el bloque.

::: tip `--fix` más de una vez

Expand Down
34 changes: 17 additions & 17 deletions packages/docs/es/migration/from-better-tailwindcss.md

Large diffs are not rendered by default.

71 changes: 50 additions & 21 deletions packages/docs/es/rules/_extras/enforce-consistent-line-wrapping.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ description: "Regla de oxlint que reporta strings de clases de Tailwind CSS que
Marca strings de clases largos para que no se desparramen más allá de un largo de línea razonable y,
cuando lo activas, los envuelve en varias líneas. Dos modos de formateo independientes: un re-wrap
basado en el width (opt-in vía `wrapLines`) y un budget de clases por línea (`classesPerLine`),
ambos con autofix en template literals y, con `wrapStrings: "jsx"`, en el string propio de un
atributo JSX (los demás string literals solo reportan — un string de JS no puede cruzar líneas).
ambos con autofix en template literals y, con `wrapStrings`, también en string literals: el string
propio de un atributo JSX en su lugar (`"jsx"`), y un string de JS convertido en template (`"all"`).
Si no, los string literals solo reportan — un string de JS no puede cruzar líneas.

DS-opcional — funciona sin `settings.tailwindcss.entryPoint`. La regla opera sobre el string crudo
de clases y no le importa qué significan, con una excepción: cuando **sí** hay un design system
Expand Down Expand Up @@ -69,12 +70,11 @@ alcance como en layout:
del budget que no siguen ese layout reportan `inconsistentWrapping`.

En un string literal de JS (`cn("…")`, `className={"…"}`, una variable) la regla reporta `tooLong`
sin fix sin importar `wrapLines`: un string de JS no puede contener un salto de línea real, y
convertirlo en un template multilínea es una decisión de criterio (extraer un componente vs. solo
wrappearlo), así que la regla saca el warning y te deja decidir. El string propio de un atributo JSX
sí se puede envolver tal cual — mira `wrapStrings`. Un fragmento de template **pegado** a un `${}`
sin whitespace (`` `${a}flex …` `` — una sola clase en runtime) tampoco se autofixea nunca:
cualquier whitespace introducido en ese borde partiría esa clase en dos.
sin fix por default: un string de JS no puede contener un salto de línea real, y convertirlo en un
template multilínea cambia el valor del string, así que eso es opt-in — mira `wrapStrings`, que
también puede envolver tal cual el string propio de un atributo JSX. Un fragmento de template
**pegado** a un `${}` sin whitespace (`` `${a}flex …` `` — una sola clase en runtime) no se
autofixea nunca: cualquier whitespace introducido en ese borde partiría esa clase en dos.

Alrededor de una interpolación, el layout `"all"` pone el run de clases que bordea un `${}` en su
**propia línea nueva** (nunca colgando inline después de la expresión), así que toda línea reescrita
Expand Down Expand Up @@ -127,8 +127,8 @@ líneas que exceden), y el fixer de `classesPerLine` corta por conteo, así que

Cantidad máxima de clases en una sola línea. Cuando se excede dentro de un template literal
(`` `…` ``), la regla autofixea envolviendo las clases en la convención bloque, en chunks de
`classesPerLine` por línea. Dentro de un string literal de JS la regla reporta `tooManyPerLine` pero
no autofixea; un string de atributo JSX también se envuelve con `wrapStrings: "jsx"`.
`classesPerLine` por línea. Dentro de un string literal la regla reporta `tooManyPerLine` sin fix, a
menos que `wrapStrings` lo cubra.

Establecer `classesPerLine` cambia el fixer de template literals a este modo por chunks y apaga el
fixer basado en el width (agrupado por variantes) — `printWidth` entonces solo reporta, y
Expand All @@ -140,12 +140,14 @@ fixer basado en el width (agrupado por variantes) — `printWidth` entonces solo

### `wrapStrings`

`"never" | "jsx"`, default `"never"`.
`"never" | "jsx" | "all"`, default `"never"`.

Qué string literals pueden envolver los fixers, además de los template literals. Con `"jsx"`, el
string propio de un atributo JSX — `className="…"`, o cualquier atributo que el plugin lee — se
envuelve en su lugar en la convención bloque, con la comilla de cierre en la indentación de la línea
del atributo:
Qué string literals pueden envolver los fixers, además de los template literals. Aplican tanto
`wrapLines` como `classesPerLine`, y un archivo con finales de línea CRLF recibe saltos CRLF.

Con `"jsx"`, el string propio de un atributo JSX — `className="…"`, o cualquier atributo que el
plugin lee — se envuelve en su lugar en la convención bloque, con la comilla de cierre en la
indentación de la línea del atributo:

```tsx
<div
Expand All @@ -158,19 +160,38 @@ del atributo:

Eso es JSX válido tal cual: en un atributo de clases los saltos de línea son espacio en blanco
común, así que no se convierte nada — es el layout que escribe `eslint-plugin-better-tailwindcss`.
Aplican tanto `wrapLines` como `classesPerLine`. Nunca un string de JS: `className={"…"}`, `cn("…")`
y las variables no pueden contener un salto de línea real, así que siguen reportando sin fix. Un
archivo con finales de línea CRLF recibe saltos CRLF.
Un string de JS — `className={"…"}`, `cn("…")`, una variable — no puede contener un salto de línea
real, así que con `"jsx"` sigue reportando sin fix.

Con `"all"`, el string JSX se envuelve igual, y un string de JS se convierte en un template literal
con el layout en bloque, como hace `eslint-plugin-better-tailwindcss`: en una llamada (`cn("…")`),
en `className={"…"}`, en un array, como valor de un objeto (`cva`, `tv`), en una rama de un ternario
o de un `&&`, y como valor de una variable.

```tsx
const card = cn(`
flex items-center justify-between rounded-md px-3 py-1
text-sm shadow-md
`)
```

Una clave de objeto (`cn({ "…": isActive })`) y un operando de `+` nunca se convierten en template,
y tampoco un string que tenga una secuencia de escape, un backtick o `${`, que un template lee
distinto: esos siguen reportando sin fix. El valor del string gana los saltos de línea y la
indentación. En una lista de clases eso es espacio en blanco, pero si tu código usa un string de
clases como otra cosa — divide o compara una variable que coincide con `variablePatterns` — quédate
en `"jsx"`.

Si oxfmt formatea tus archivos con `sortTailwindcss`, pon su `preserveWhitespace: true`: por default
colapsa el espacio en blanco de los atributos de clases, saltos de línea del bloque incluidos, y
cada uno deshace lo del otro (mira [/interop](/interop)).
colapsa el espacio en blanco de los strings de clases, tanto el de un atributo JSX como el template
de un helper, saltos de línea del bloque incluidos, y cada uno deshace lo del otro (mira
[/interop](/interop)).

```jsonc
{
"tailwindcss/enforce-consistent-line-wrapping": [
"error",
{ "printWidth": 100, "wrapLines": "overWidth", "wrapStrings": "jsx" },
{ "printWidth": 100, "wrapLines": "overWidth", "wrapStrings": "all" },
],
}
```
Expand Down Expand Up @@ -212,6 +233,14 @@ const className = `flex items-center justify-between p-4 m-2 bg-white`
// p-4 m-2 bg-white
// " />

// Un string de JS con wrapStrings: "all" — se convierte en un template literal
// options: { "classesPerLine": 3, "wrapStrings": "all" }
const card = cn("flex items-center justify-between p-4 m-2 bg-white")
// → const card = cn(`
// flex items-center justify-between
// p-4 m-2 bg-white
// `)

// printWidth: 40 con wrapLines: "overWidth" — SOLO se re-envuelve la
// línea que excede; las líneas conformes alrededor quedan tal como estaban
// options: { "printWidth": 40, "wrapLines": "overWidth" }
Expand Down
71 changes: 50 additions & 21 deletions packages/docs/es/rules/enforce-consistent-line-wrapping.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@ clases por línea, y puede partirlos en varias líneas.
Marca strings de clases largos para que no se desparramen más allá de un largo de línea razonable y,
cuando lo activas, los envuelve en varias líneas. Dos modos de formateo independientes: un re-wrap
basado en el width (opt-in vía `wrapLines`) y un budget de clases por línea (`classesPerLine`),
ambos con autofix en template literals y, con `wrapStrings: "jsx"`, en el string propio de un
atributo JSX (los demás string literals solo reportan — un string de JS no puede cruzar líneas).
ambos con autofix en template literals y, con `wrapStrings`, también en string literals: el string
propio de un atributo JSX en su lugar (`"jsx"`), y un string de JS convertido en template (`"all"`).
Si no, los string literals solo reportan — un string de JS no puede cruzar líneas.

DS-opcional — funciona sin `settings.tailwindcss.entryPoint`. La regla opera sobre el string crudo
de clases y no le importa qué significan, con una excepción: cuando **sí** hay un design system
Expand Down Expand Up @@ -81,12 +82,11 @@ alcance como en layout:
del budget que no siguen ese layout reportan `inconsistentWrapping`.

En un string literal de JS (`cn("…")`, `className={"…"}`, una variable) la regla reporta `tooLong`
sin fix sin importar `wrapLines`: un string de JS no puede contener un salto de línea real, y
convertirlo en un template multilínea es una decisión de criterio (extraer un componente vs. solo
wrappearlo), así que la regla saca el warning y te deja decidir. El string propio de un atributo JSX
sí se puede envolver tal cual — mira `wrapStrings`. Un fragmento de template **pegado** a un `${}`
sin whitespace (`` `${a}flex …` `` — una sola clase en runtime) tampoco se autofixea nunca:
cualquier whitespace introducido en ese borde partiría esa clase en dos.
sin fix por default: un string de JS no puede contener un salto de línea real, y convertirlo en un
template multilínea cambia el valor del string, así que eso es opt-in — mira `wrapStrings`, que
también puede envolver tal cual el string propio de un atributo JSX. Un fragmento de template
**pegado** a un `${}` sin whitespace (`` `${a}flex …` `` — una sola clase en runtime) no se
autofixea nunca: cualquier whitespace introducido en ese borde partiría esa clase en dos.

Alrededor de una interpolación, el layout `"all"` pone el run de clases que bordea un `${}` en su
**propia línea nueva** (nunca colgando inline después de la expresión), así que toda línea reescrita
Expand Down Expand Up @@ -139,8 +139,8 @@ líneas que exceden), y el fixer de `classesPerLine` corta por conteo, así que

Cantidad máxima de clases en una sola línea. Cuando se excede dentro de un template literal
(`` `…` ``), la regla autofixea envolviendo las clases en la convención bloque, en chunks de
`classesPerLine` por línea. Dentro de un string literal de JS la regla reporta `tooManyPerLine` pero
no autofixea; un string de atributo JSX también se envuelve con `wrapStrings: "jsx"`.
`classesPerLine` por línea. Dentro de un string literal la regla reporta `tooManyPerLine` sin fix, a
menos que `wrapStrings` lo cubra.

Establecer `classesPerLine` cambia el fixer de template literals a este modo por chunks y apaga el
fixer basado en el width (agrupado por variantes) — `printWidth` entonces solo reporta, y
Expand All @@ -152,12 +152,14 @@ fixer basado en el width (agrupado por variantes) — `printWidth` entonces solo

### `wrapStrings`

`"never" | "jsx"`, default `"never"`.
`"never" | "jsx" | "all"`, default `"never"`.

Qué string literals pueden envolver los fixers, además de los template literals. Con `"jsx"`, el
string propio de un atributo JSX — `className="…"`, o cualquier atributo que el plugin lee — se
envuelve en su lugar en la convención bloque, con la comilla de cierre en la indentación de la línea
del atributo:
Qué string literals pueden envolver los fixers, además de los template literals. Aplican tanto
`wrapLines` como `classesPerLine`, y un archivo con finales de línea CRLF recibe saltos CRLF.

Con `"jsx"`, el string propio de un atributo JSX — `className="…"`, o cualquier atributo que el
plugin lee — se envuelve en su lugar en la convención bloque, con la comilla de cierre en la
indentación de la línea del atributo:

```tsx
<div
Expand All @@ -170,19 +172,38 @@ del atributo:

Eso es JSX válido tal cual: en un atributo de clases los saltos de línea son espacio en blanco
común, así que no se convierte nada — es el layout que escribe `eslint-plugin-better-tailwindcss`.
Aplican tanto `wrapLines` como `classesPerLine`. Nunca un string de JS: `className={"…"}`, `cn("…")`
y las variables no pueden contener un salto de línea real, así que siguen reportando sin fix. Un
archivo con finales de línea CRLF recibe saltos CRLF.
Un string de JS — `className={"…"}`, `cn("…")`, una variable — no puede contener un salto de línea
real, así que con `"jsx"` sigue reportando sin fix.

Con `"all"`, el string JSX se envuelve igual, y un string de JS se convierte en un template literal
con el layout en bloque, como hace `eslint-plugin-better-tailwindcss`: en una llamada (`cn("…")`),
en `className={"…"}`, en un array, como valor de un objeto (`cva`, `tv`), en una rama de un ternario
o de un `&&`, y como valor de una variable.

```tsx
const card = cn(`
flex items-center justify-between rounded-md px-3 py-1
text-sm shadow-md
`)
```

Una clave de objeto (`cn({ "…": isActive })`) y un operando de `+` nunca se convierten en template,
y tampoco un string que tenga una secuencia de escape, un backtick o `${`, que un template lee
distinto: esos siguen reportando sin fix. El valor del string gana los saltos de línea y la
indentación. En una lista de clases eso es espacio en blanco, pero si tu código usa un string de
clases como otra cosa — divide o compara una variable que coincide con `variablePatterns` — quédate
en `"jsx"`.

Si oxfmt formatea tus archivos con `sortTailwindcss`, pon su `preserveWhitespace: true`: por default
colapsa el espacio en blanco de los atributos de clases, saltos de línea del bloque incluidos, y
cada uno deshace lo del otro (mira [/interop](/interop)).
colapsa el espacio en blanco de los strings de clases, tanto el de un atributo JSX como el template
de un helper, saltos de línea del bloque incluidos, y cada uno deshace lo del otro (mira
[/interop](/interop)).

```jsonc
{
"tailwindcss/enforce-consistent-line-wrapping": [
"error",
{ "printWidth": 100, "wrapLines": "overWidth", "wrapStrings": "jsx" },
{ "printWidth": 100, "wrapLines": "overWidth", "wrapStrings": "all" },
],
}
```
Expand Down Expand Up @@ -224,6 +245,14 @@ const className = `flex items-center justify-between p-4 m-2 bg-white`
// p-4 m-2 bg-white
// " />

// Un string de JS con wrapStrings: "all" — se convierte en un template literal
// options: { "classesPerLine": 3, "wrapStrings": "all" }
const card = cn("flex items-center justify-between p-4 m-2 bg-white")
// → const card = cn(`
// flex items-center justify-between
// p-4 m-2 bg-white
// `)

// printWidth: 40 con wrapLines: "overWidth" — SOLO se re-envuelve la
// línea que excede; las líneas conformes alrededor quedan tal como estaban
// options: { "printWidth": 40, "wrapLines": "overWidth" }
Expand Down
Loading
Loading