@pandacss/eslint-plugin 0.3.2 → 2.0.0-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/{LICENSE → LICENSE.md} +1 -1
- package/README.md +219 -0
- package/dist/chunk-DREIC7ND.js +1173 -0
- package/dist/index.d.ts +199 -0
- package/dist/index.js +143 -2535
- package/dist/oxlint.d.ts +12 -0
- package/dist/oxlint.js +11 -0
- package/dist/shared-B-c4H6nv.d.ts +126 -0
- package/package.json +45 -32
- package/dist/chunk-KBOB3H6E.mjs +0 -20
- package/dist/index.mjs +0 -2834
- package/dist/utils/worker.js +0 -4103
- package/dist/utils/worker.mjs +0 -4090
package/{LICENSE → LICENSE.md}
RENAMED
package/README.md
ADDED
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
# @pandacss/eslint-plugin
|
|
2
|
+
|
|
3
|
+
ESLint rules for Panda CSS that read your actual config. They know your tokens, recipes, patterns, and utilities — so
|
|
4
|
+
they catch a typo'd token, a deprecated recipe, or a hardcoded color that should be a token. 🐼
|
|
5
|
+
|
|
6
|
+
There's no JSON to generate first. The plugin loads your `panda.config.ts` once and lints against it.
|
|
7
|
+
|
|
8
|
+
> Beta. ESLint v9 flat config only. Most rules are report-only; a few add fixes/suggestions (noted below).
|
|
9
|
+
|
|
10
|
+
## Install
|
|
11
|
+
|
|
12
|
+
```sh
|
|
13
|
+
pnpm add -D @pandacss/eslint-plugin
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
You need ESLint 9 or later.
|
|
17
|
+
|
|
18
|
+
## Setup
|
|
19
|
+
|
|
20
|
+
Add the recommended config to `eslint.config.mjs`. Loading your Panda config is async, and ESLint
|
|
21
|
+
[supports a flat config that resolves to a Promise](https://eslint.org/docs/latest/use/configure/configuration-files),
|
|
22
|
+
so `await` it (top-level `await` works in flat config):
|
|
23
|
+
|
|
24
|
+
```js
|
|
25
|
+
import panda from '@pandacss/eslint-plugin'
|
|
26
|
+
|
|
27
|
+
export default [await panda.configs.recommended({ configPath: './panda.config.ts' })]
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
That's it. The rules now run against your project's tokens, recipes, and utilities.
|
|
31
|
+
|
|
32
|
+
Top-level `await` works in `eslint.config.mjs` (or `.js` with `"type": "module"`) and in `eslint.config.ts` (jiti ≥2 /
|
|
33
|
+
Node ≥22.13 / Deno / Bun). In a CommonJS `eslint.config.cjs`, export a Promise instead — ESLint resolves it:
|
|
34
|
+
|
|
35
|
+
```js
|
|
36
|
+
module.exports = (async () => {
|
|
37
|
+
const panda = (await import('@pandacss/eslint-plugin')).default
|
|
38
|
+
return [await panda.configs.recommended({ configPath: './panda.config.ts' })]
|
|
39
|
+
})()
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
The recommended config scopes itself to JS/TS/JSX files and **does not set a parser** — use your project's existing
|
|
43
|
+
parser. Most TS setups already have one via [`typescript-eslint`](https://typescript-eslint.io/), and framework projects
|
|
44
|
+
via their ESLint preset (`eslint-plugin-vue`, `astro-eslint-parser`, etc.). Panda's rules read source text directly, so
|
|
45
|
+
any parser that produces a `Program` works.
|
|
46
|
+
|
|
47
|
+
To lint framework files (`.vue`, `.svelte`, `.astro`), opt them in via `files` once their parser is configured:
|
|
48
|
+
|
|
49
|
+
```js
|
|
50
|
+
await panda.configs.recommended({ configPath: './panda.config.ts', files: ['**/*.{ts,tsx,vue}'] })
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Enabling opt-in rules / changing severities
|
|
54
|
+
|
|
55
|
+
`recommended` binds every rule under the `@pandacss` plugin, so add opt-in rules (or tweak severities) in your own
|
|
56
|
+
`rules` block after it:
|
|
57
|
+
|
|
58
|
+
```js
|
|
59
|
+
export default [
|
|
60
|
+
await panda.configs.recommended({ configPath: './panda.config.ts' }),
|
|
61
|
+
{ rules: { '@pandacss/consistent-property-style': ['error', { style: 'shorthand' }] } },
|
|
62
|
+
]
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Monorepos
|
|
66
|
+
|
|
67
|
+
Call `recommended` once per Panda config and scope each to its package via `files`:
|
|
68
|
+
|
|
69
|
+
```js
|
|
70
|
+
export default [
|
|
71
|
+
{
|
|
72
|
+
...(await panda.configs.recommended({ configPath: './packages/web/panda.config.ts' })),
|
|
73
|
+
files: ['packages/web/**'],
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
...(await panda.configs.recommended({ configPath: './packages/app/panda.config.ts' })),
|
|
77
|
+
files: ['packages/app/**'],
|
|
78
|
+
},
|
|
79
|
+
]
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
> The Panda config is loaded once and cached; a long-running editor session won't pick up `panda.config` edits until
|
|
83
|
+
> ESLint restarts.
|
|
84
|
+
|
|
85
|
+
### oxlint
|
|
86
|
+
|
|
87
|
+
The same rules run under [oxlint](https://oxc.rs) via its ESLint-compatible JS plugins (alpha — needs `oxlint` +
|
|
88
|
+
`@oxlint/plugins`). Point `jsPlugins` at the `@pandacss/eslint-plugin/oxlint` entry and enable the rules in
|
|
89
|
+
`.oxlintrc.json`:
|
|
90
|
+
|
|
91
|
+
```json
|
|
92
|
+
{
|
|
93
|
+
"jsPlugins": ["@pandacss/eslint-plugin/oxlint"],
|
|
94
|
+
"rules": {
|
|
95
|
+
"@pandacss/no-invalid-nesting": "error",
|
|
96
|
+
"@pandacss/no-debug": "warn",
|
|
97
|
+
"@pandacss/prefer-token": ["warn", { "categories": ["colors"] }]
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
The entry auto-discovers `panda.config.*` from the working directory; set `PANDA_CONFIG_PATH` to point at a config in a
|
|
103
|
+
non-standard location.
|
|
104
|
+
|
|
105
|
+
**Single config per run.** Unlike the ESLint flat config (where you compose several `recommended({ configPath })`
|
|
106
|
+
entries), oxlint loads a JS plugin once and binds one Panda project. For a custom path or a monorepo with several
|
|
107
|
+
configs, write a tiny local plugin instead of using the entry, hardcoding the `configPath`:
|
|
108
|
+
|
|
109
|
+
```js
|
|
110
|
+
// oxlint-panda.mjs
|
|
111
|
+
import { createPandaPlugin } from '@pandacss/eslint-plugin'
|
|
112
|
+
|
|
113
|
+
const { rules } = await createPandaPlugin({ configPath: './panda.config.ts' })
|
|
114
|
+
export default { meta: { name: '@pandacss' }, rules }
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
```json
|
|
118
|
+
{ "jsPlugins": ["./oxlint-panda.mjs"], "rules": { "@pandacss/no-invalid-nesting": "error" } }
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
`oxlint.config.ts` (via `defineConfig` from `oxlint`, Node ≥22.18) works the same way — plugins are still referenced by
|
|
122
|
+
path, so the setup is identical.
|
|
123
|
+
|
|
124
|
+
## Rules
|
|
125
|
+
|
|
126
|
+
These rules are on in `recommended`:
|
|
127
|
+
|
|
128
|
+
- `no-invalid-token-paths` (error) — a token reference that doesn't exist, e.g. `token('colors.ghost')`.
|
|
129
|
+
- `no-invalid-nesting` (error) — a nested selector missing `&` (`':hover'` instead of `'&:hover'`), which Panda silently
|
|
130
|
+
ignores. Suggests prefixing `&`.
|
|
131
|
+
- `file-not-included` (error) — a file uses Panda but sits outside your config `include`, so its styles never get
|
|
132
|
+
generated.
|
|
133
|
+
- `no-deprecated` (warn) — use of a deprecated token, utility, recipe, or pattern. If you set
|
|
134
|
+
`deprecated: 'use X instead'` in config, that message shows up in the lint error.
|
|
135
|
+
- `prefer-token` (warn) — a raw value where a token exists, with the token to use. In `recommended` it's scoped to
|
|
136
|
+
colors (the old `no-hardcoded-color`); widen it with `categories` (see below).
|
|
137
|
+
- `no-debug` (warn) — a leftover `debug: true`.
|
|
138
|
+
- `extraction-diagnostics` (warn) — parse or extraction problems Panda hit in the file.
|
|
139
|
+
|
|
140
|
+
The rest are off by default. Turn them on per project:
|
|
141
|
+
|
|
142
|
+
- `no-important` — `!important` in styles.
|
|
143
|
+
- `no-margin-properties` — margin props; nudges you toward `gap` and layout patterns.
|
|
144
|
+
- `no-physical-properties` — physical props that have logical equivalents (`left` → `insetInlineStart`).
|
|
145
|
+
- `no-shorthand-longhand-mix` — a shorthand and one of its longhands in the same block (`margin` + `marginLeft`); the
|
|
146
|
+
longhand wins regardless of source order. Takes `ignore` (groups to allow).
|
|
147
|
+
- `consistent-property-style` — enforce one property style: Panda shorthand aliases (`ml`) or longhand canonical names
|
|
148
|
+
(`marginLeft`). Autofixable. Takes `style: 'shorthand' | 'longhand'` (default `longhand`) and `ignore`.
|
|
149
|
+
- `prefer-text-style` — a style object setting two or more typography properties that should be one `textStyle` token.
|
|
150
|
+
|
|
151
|
+
Enable an opt-in rule like any other:
|
|
152
|
+
|
|
153
|
+
```js
|
|
154
|
+
import panda from '@pandacss/eslint-plugin'
|
|
155
|
+
|
|
156
|
+
export default [
|
|
157
|
+
await panda.configs.recommended({ configPath: './panda.config.ts' }),
|
|
158
|
+
{ rules: { '@pandacss/no-important': 'error' } },
|
|
159
|
+
]
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Options
|
|
163
|
+
|
|
164
|
+
`no-deprecated` takes a `kinds` option to narrow what it checks:
|
|
165
|
+
|
|
166
|
+
```js
|
|
167
|
+
{ rules: { '@pandacss/no-deprecated': ['warn', { kinds: ['tokens', 'recipes'] }] } }
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Valid kinds: `tokens`, `utilities`, `recipes`, `patterns`. All are checked by default.
|
|
171
|
+
|
|
172
|
+
`prefer-token` takes `categories` (which token categories to enforce; defaults to all) and `allow` (raw values to
|
|
173
|
+
permit):
|
|
174
|
+
|
|
175
|
+
```js
|
|
176
|
+
{ rules: { '@pandacss/prefer-token': ['warn', { categories: ['colors', 'spacing'], allow: ['transparent'] }] } }
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
It lists the tokens that carry the value and offers each as an editor quick-fix, so you pick — semantic and primitive
|
|
180
|
+
both shown (semantic first), themed tokens marked `(themed)`. It matches equivalent forms (`#FFF` == `#ffffff`, `16px`
|
|
181
|
+
== `1rem`):
|
|
182
|
+
|
|
183
|
+
```
|
|
184
|
+
Hardcoded colors value "#f00". Matching tokens: fg.error, red.500.
|
|
185
|
+
💡 Use the token "fg.error"
|
|
186
|
+
💡 Use the token "red.500"
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Quick-fixes apply to each offending leaf — flat literals (`color: '#f00'`), values nested in conditions
|
|
190
|
+
(`color: { base: '#f00' }`), and responsive-array elements (`color: ['#f00', ...]`). Coverage spans `css()`, style
|
|
191
|
+
props, and recipe styles in `cva()` / `sva()` / `styled('div', { ... })` (`base`, `variants`, `compoundVariants`).
|
|
192
|
+
|
|
193
|
+
### Migrating from `no-hardcoded-color`
|
|
194
|
+
|
|
195
|
+
`no-hardcoded-color` is now `prefer-token` scoped to colors. Replace it with:
|
|
196
|
+
|
|
197
|
+
```js
|
|
198
|
+
{ rules: { '@pandacss/prefer-token': ['warn', { categories: ['colors'] }] } }
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
`recommended` already does this, so if you use `configs.recommended` there's nothing to change.
|
|
202
|
+
|
|
203
|
+
## Settings
|
|
204
|
+
|
|
205
|
+
The plugin finds your config in this order:
|
|
206
|
+
|
|
207
|
+
1. `settings.panda.configPath`
|
|
208
|
+
2. `settings['@pandacss/configPath']` (migration alias)
|
|
209
|
+
3. the nearest Panda config to the file being linted
|
|
210
|
+
|
|
211
|
+
```js
|
|
212
|
+
export default [panda.configs.recommended(), { settings: { panda: { configPath: './panda.config.ts' } } }]
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
## How it works
|
|
216
|
+
|
|
217
|
+
The plugin builds one Panda compiler per config and reuses it across files. Rules don't re-parse — they ask the compiler
|
|
218
|
+
what each file means to Panda (which calls are `css`, which tag is a recipe, which value resolved to a token) and report
|
|
219
|
+
on the ESLint nodes. Config loading happens once, up front, so the rule visitors stay synchronous and fast.
|