@pandacss/eslint-plugin 0.3.2 → 2.0.0-beta.5

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.
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2021 Chakra UI
3
+ Copyright (c) 2023 Chakra Systems Inc.
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
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.