Skip to content
Merged
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ The plugin auto-detects classRegex patterns from your IDE configuration (`.vscod
| `tailwindPreserveWhitespace` | `boolean` | `false` | Preserve whitespace in class attributes |
| `tailwindPreserveDuplicates` | `boolean` | `false` | Keep duplicate classes |
| `tailwindPropertyOrder` | `string` | `""` | Path to stylelint-order compatible config for custom CSS property ordering |
| `tailwindClassOrder` | `string` | `""` | Bucket-based class ordering (unknown / tailwind / regex patterns). Path to JS/JSON file, or JSON-encoded string starting with `[` |

See [Options documentation](docs/options.md) for detailed descriptions and examples.

Expand Down
108 changes: 104 additions & 4 deletions docs/options.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,99 @@ Input: text-red-500 p-4 md:flex flex md:p-4 w-5
Output: flex w-5 p-4 text-red-500 md:flex md:p-4
```

## `tailwindClassOrder`

**Type:** `string` · **Default:** `""` (implicit `["unknown", "tailwind"]`)

Configurable class ordering through a list of **buckets**. Membership follows a fixed priority rule — explicit `{pattern}` buckets always win over the `"unknown"` / `"tailwind"` catchalls. The **order you write buckets in your config controls the order of groups in the output**, not the matching priority.

### Config value: path or JSON-encoded string

Prettier CLI cannot accept a raw JSON array for non-array options (arrays are silently collapsed to their last element), so the option value must be a **string**:

- **Path to an external file** (recommended):
```json
{ "tailwindClassOrder": "./tailwind-class-order.json" }
```
- **JSON-encoded string** starting with `[`:
```json
{ "tailwindClassOrder": "[[\"unknown\", {\"pattern\":\"^js-\"}, \"tailwind\"], {\"unspecified\":\"top\"}]" }
```

Path is resolved relative to your `.prettierrc` location (same resolver as `tailwindPropertyOrder`).

### Config shape

Tuple form `[items, secondaryOptions]` (stylelint-order style):

```json
[
["unknown", { "pattern": "^icon(?:--|$)" }, "tailwind", { "pattern": "^js-" }],
{ "unspecified": "top" }
]
```

A flat array of buckets is also accepted (secondary options default to `{ "unspecified": "top" }`):

```json
["unknown", "tailwind", { "pattern": "^js-" }]
```

### Bucket types

- **`"unknown"`** — catchall for classes Tailwind doesn’t recognize (null bigint). Stable input order. Only claims classes no pattern matched.
- **`"tailwind"`** (alias `"tailwindcss"`) — catchall for known Tailwind utilities (non-null bigint). Sorted by Tailwind order (and `tailwindPropertyOrder` if set). Only claims classes no pattern matched.
- **`{ "pattern": "^..." }`** — regex match against the class name. Stable input order. Anchors (`^`, `$`) must be written explicitly — no implicit anchoring.

### How matching works

1. **Phase 1 — priority assignment.** For each class:
- Try every `{pattern}` bucket (in config order, first match wins). This applies regardless of whether a pattern appears before or after `"tailwind"` / `"unknown"` in the config.
- If no pattern matched: assign to the first `"tailwind"` bucket (non-null bigint) or the first `"unknown"` bucket (null bigint). Otherwise leave unspecified.
2. **Phase 2 — emit in config order.** Iterate buckets in the order written by the user; emit their members. The `"tailwind"` bucket is sorted; pattern and `"unknown"` buckets preserve input order. Unspecified classes go to the front or back per `unspecified`.

### Default

When not set, the plugin behaves as if configured with `[["unknown", "tailwind"], { "unspecified": "top" }]` — unknown classes first, then Tailwind utilities sorted by class order.

### Use cases

**1. Push JS hooks to the end**

```json
["unknown", "tailwind", { "pattern": "^js-" }]
```

```
Input: js-toggle flex mt-4 custom-class
Output: custom-class flex mt-4 js-toggle
```

**2. Keep BEM modifiers next to the base class**

Both `icon` and `icon--check-circle` match `^icon(?:--|$)` and land in the same bucket, preserving input order:

```json
[{ "pattern": "^icon(?:--|$)" }, "unknown", "tailwind"]
```

```
Input: flex icon icon--check-circle mt-4
Output: icon icon--check-circle flex mt-4
```

**3. Component-like utilities first**

Utilities that set multiple CSS properties (e.g. `h1`, `grid-cols-center`) can be extracted ahead of single-purpose utilities:

```json
["unknown", { "pattern": "^(h[1-6]|grid-cols-)" }, "tailwind"]
```

### Interaction with `tailwindPropertyOrder`

Property order only applies inside the `"tailwind"` bucket. Pattern and `"unknown"` buckets always keep input order. To sort BEM modifiers by a custom scheme, use separate patterns (e.g. `^icon$` before `^icon--`).

## `tailwindAttributes`

**Type:** `string[]` · **Default:** `[]`
Expand Down Expand Up @@ -145,19 +238,26 @@ Controls how whitespace separators between `n:class` tokens are handled when tok
'mt-4'">
```

**`normalize-barriers`** (default) — Separators within sortable groups are normalized to `, `. Separators after barrier tokens (conditionals, variables, multi-class strings) are preserved.
**`normalize-barriers`** (default) — Within sortable groups: newlines are preserved (so user-intended multi-line layout survives sorting); horizontal-only separators collapse to `, `. Separators after barrier tokens (conditionals, variables, multi-class strings) are always preserved.

```latte
{* Input *}
{* Input — multi-line *}
<div n:class="'text-left',
'flex',
$active ? 'font-bold',
'mt-4'">

{* Output *}
<div n:class="'flex', 'text-left',
{* Output — newlines kept *}
<div n:class="'flex',
'text-left',
$active ? 'font-bold',
'mt-4'">

{* Input — single-line with extra spaces *}
<div n:class="'text-left', 'flex', $active ? 'font-bold'">

{* Output — collapses to single-space separator *}
<div n:class="'flex', 'text-left', $active ? 'font-bold'">
```

**`normalize`** &mdash; All separators normalized to `, ` (single-line output).
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "prettier-plugin-latte-tailwindcss",
"version": "0.5.0",
"version": "0.6.0",
"description": "Prettier plugin for sorting Tailwind CSS v4 classes in Latte v3 templates",
"type": "module",
"main": "./dist/index.cjs",
Expand Down
Loading