@letstri/oxc-config 0.5.0 → 0.7.0
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/README.md +25 -77
- package/dist/index.d.mts +41 -15
- package/dist/index.mjs +25 -20
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -29,46 +29,12 @@ npx oxc-config init --vscode --zed # just the editor settings
|
|
|
29
29
|
|
|
30
30
|
With flags, only the chosen targets run; with none in a non-interactive shell,
|
|
31
31
|
all four run. Config files are skipped if they already exist (`--force` to
|
|
32
|
-
overwrite); editor settings are deep-merged into any existing
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
<details>
|
|
40
|
-
<summary>Show prompt</summary>
|
|
41
|
-
|
|
42
|
-
````text
|
|
43
|
-
Set up @letstri/oxc-config (oxlint + oxfmt) in this project:
|
|
44
|
-
|
|
45
|
-
1. Install dev deps: `@letstri/oxc-config oxlint oxfmt`.
|
|
46
|
-
2. Remove ESLint and Prettier: their configs, deps, and scripts.
|
|
47
|
-
3. Create `oxlint.config.ts`:
|
|
48
|
-
```ts
|
|
49
|
-
import { oxlintConfig } from '@letstri/oxc-config'
|
|
50
|
-
|
|
51
|
-
export default oxlintConfig()
|
|
52
|
-
```
|
|
53
|
-
4. Create `oxfmt.config.ts`:
|
|
54
|
-
```ts
|
|
55
|
-
import { oxfmtConfig } from '@letstri/oxc-config'
|
|
56
|
-
|
|
57
|
-
export default oxfmtConfig()
|
|
58
|
-
```
|
|
59
|
-
5. Add package.json scripts:
|
|
60
|
-
- "lint": "oxlint"
|
|
61
|
-
- "lint:fix": "oxlint --fix"
|
|
62
|
-
- "format": "oxfmt"
|
|
63
|
-
- "format:check": "oxfmt --check"
|
|
64
|
-
6. Framework plugins auto-enable from the nearest package.json. If a framework
|
|
65
|
-
dep (react/vue/next/vitest/jest/typescript) lives in a nested workspace,
|
|
66
|
-
enable it manually, e.g. `oxlintConfig({ plugins: ['vue'] })`.
|
|
67
|
-
7. Add the VS Code and Zed editor settings from the @letstri/oxc-config README.
|
|
68
|
-
8. Run `pnpm lint` and `pnpm format` and fix anything reported.
|
|
69
|
-
````
|
|
70
|
-
|
|
71
|
-
</details>
|
|
32
|
+
overwrite); editor settings (VS Code + Zed) are deep-merged into any existing
|
|
33
|
+
files, so your other settings are kept.
|
|
34
|
+
|
|
35
|
+
VS Code also needs the [`oxc.oxc-vscode`](https://marketplace.visualstudio.com/items?itemName=oxc.oxc-vscode)
|
|
36
|
+
extension (the CLI adds it to `.vscode/extensions.json`). Zed has the oxc
|
|
37
|
+
language servers built in.
|
|
72
38
|
|
|
73
39
|
## Usage
|
|
74
40
|
|
|
@@ -126,16 +92,16 @@ export default oxlintConfig({ rules: { 'no-console': 'off' } }, { plugins: ['vue
|
|
|
126
92
|
|
|
127
93
|
### Tailwind
|
|
128
94
|
|
|
129
|
-
`
|
|
130
|
-
[`
|
|
95
|
+
`tailwindPlugin({ entryPoint })` returns a config chunk for
|
|
96
|
+
[`oxlint-tailwindcss`](https://github.com/sergioazoc/oxlint-tailwindcss) (Tailwind v4).
|
|
131
97
|
Pass it as an argument to `oxlintConfig`:
|
|
132
98
|
|
|
133
99
|
```ts
|
|
134
|
-
import { oxlintConfig,
|
|
100
|
+
import { oxlintConfig, tailwindPlugin } from '@letstri/oxc-config'
|
|
135
101
|
|
|
136
102
|
export default oxlintConfig(
|
|
137
103
|
{ plugins: ['react', 'jsx-a11y'] },
|
|
138
|
-
|
|
104
|
+
tailwindPlugin({ entryPoint: 'app/globals.css' }),
|
|
139
105
|
)
|
|
140
106
|
```
|
|
141
107
|
|
|
@@ -145,47 +111,29 @@ ones above rather than overwriting them.
|
|
|
145
111
|
Options:
|
|
146
112
|
|
|
147
113
|
- `entryPoint` (required) — your Tailwind entry CSS, so the plugin can resolve
|
|
148
|
-
class names.
|
|
114
|
+
class names. In a monorepo, pass an array of glob → CSS mappings (last match
|
|
115
|
+
wins, so end with a `'**'` catch-all):
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
tailwindPlugin({
|
|
119
|
+
entryPoint: [
|
|
120
|
+
{ files: 'packages/ui/**', use: 'packages/ui/src/styles.css' },
|
|
121
|
+
{ files: '**', use: 'src/global.css' },
|
|
122
|
+
],
|
|
123
|
+
})
|
|
124
|
+
```
|
|
125
|
+
|
|
149
126
|
- `ignoreClasses` — class names to exempt from `no-unknown-classes` (e.g. classes
|
|
150
127
|
a component library generates that the plugin can't resolve):
|
|
151
128
|
|
|
152
129
|
```ts
|
|
153
|
-
|
|
130
|
+
tailwindPlugin({ entryPoint: 'app/globals.css', ignoreClasses: ['toaster'] })
|
|
154
131
|
```
|
|
155
132
|
|
|
156
133
|
The plugin is an **optional peer dependency** — install it yourself:
|
|
157
134
|
|
|
158
135
|
```bash
|
|
159
|
-
pnpm add -D
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
If the plugin is missing, `tailwind()` throws with an install hint.
|
|
163
|
-
|
|
164
|
-
## Editor setup
|
|
165
|
-
|
|
166
|
-
Both editors use the official [oxc](https://oxc.rs) tooling — `oxlint` for
|
|
167
|
-
linting and `oxfmt` for formatting — replacing ESLint and Prettier.
|
|
168
|
-
|
|
169
|
-
`oxc-config init` writes (or updates) the editor configs for you, deep-merging
|
|
170
|
-
into any existing files so your other settings are kept:
|
|
171
|
-
|
|
172
|
-
```bash
|
|
173
|
-
# both editors
|
|
174
|
-
pnpm exec oxc-config init --vscode --zed
|
|
136
|
+
pnpm add -D oxlint-tailwindcss
|
|
175
137
|
```
|
|
176
138
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
### VS Code
|
|
180
|
-
|
|
181
|
-
Install the [`oxc.oxc-vscode`](https://marketplace.visualstudio.com/items?itemName=oxc.oxc-vscode)
|
|
182
|
-
extension (`init --vscode` also adds it to `.vscode/extensions.json`). It writes
|
|
183
|
-
`.vscode/settings.json` — oxlint as linter, oxfmt as the default formatter with
|
|
184
|
-
format-on-save, and Prettier's import organization turned off.
|
|
185
|
-
|
|
186
|
-
### Zed
|
|
187
|
-
|
|
188
|
-
Zed ships with the oxc language servers built in, so no extension is needed.
|
|
189
|
-
`init --zed` writes `.zed/settings.json` — oxfmt as the formatter (with
|
|
190
|
-
`source.fixAll.oxc` on save for JS/TS) and Prettier disabled, across the file
|
|
191
|
-
types oxfmt supports.
|
|
139
|
+
If the plugin is missing, `tailwindPlugin()` throws with an install hint.
|
package/dist/index.d.mts
CHANGED
|
@@ -1,7 +1,21 @@
|
|
|
1
1
|
import { defineConfig } from "oxlint";
|
|
2
2
|
import { defineConfig as defineConfig$1 } from "oxfmt";
|
|
3
3
|
//#region src/oxlint.d.ts
|
|
4
|
-
type OxlintOptions
|
|
4
|
+
type OxlintOptions = Parameters<typeof defineConfig>[0];
|
|
5
|
+
type OxlintPlugin = NonNullable<NonNullable<OxlintOptions>['plugins']>[number];
|
|
6
|
+
declare const basePlugins: readonly ["import", "unicorn", "jsdoc", "node", "promise", "oxc"];
|
|
7
|
+
/**
|
|
8
|
+
* Plugins always enabled by the base config — excluded from the `plugins` you
|
|
9
|
+
* can add, since listing them again is redundant.
|
|
10
|
+
*/
|
|
11
|
+
type BasePlugin = (typeof basePlugins)[number];
|
|
12
|
+
/**
|
|
13
|
+
* Oxlint config accepted by {@link oxlintConfig}. Same as oxlint's own config,
|
|
14
|
+
* but `plugins` can't include the always-on base plugins.
|
|
15
|
+
*/
|
|
16
|
+
type OxlintConfig = Omit<NonNullable<OxlintOptions>, 'plugins'> & {
|
|
17
|
+
plugins?: Exclude<OxlintPlugin, BasePlugin>[];
|
|
18
|
+
};
|
|
5
19
|
/**
|
|
6
20
|
* Build an oxlint config.
|
|
7
21
|
*
|
|
@@ -10,8 +24,9 @@ type OxlintOptions$1 = Parameters<typeof defineConfig>[0];
|
|
|
10
24
|
* plugin whose dependency lives elsewhere — e.g. a nested workspace like
|
|
11
25
|
* `apps/web/package.json` — add it through `plugins`.
|
|
12
26
|
*
|
|
13
|
-
* Pass any number of config objects; they are deep-merged (arrays concatenated
|
|
14
|
-
* so pieces like {@link
|
|
27
|
+
* Pass any number of config objects; they are deep-merged (arrays concatenated,
|
|
28
|
+
* with `plugins` de-duplicated), so pieces like {@link tailwindPlugin} compose
|
|
29
|
+
* without clobbering each other.
|
|
15
30
|
*
|
|
16
31
|
* @example
|
|
17
32
|
* ```ts
|
|
@@ -28,11 +43,11 @@ type OxlintOptions$1 = Parameters<typeof defineConfig>[0];
|
|
|
28
43
|
* // compose Tailwind — its plugins merge with the ones above, not overwrite
|
|
29
44
|
* export default oxlintConfig(
|
|
30
45
|
* { plugins: ['react', 'jsx-a11y'] },
|
|
31
|
-
*
|
|
46
|
+
* tailwindPlugin({ entryPoint: 'app/globals.css' }),
|
|
32
47
|
* )
|
|
33
48
|
* ```
|
|
34
49
|
*/
|
|
35
|
-
declare function oxlintConfig(...overrides:
|
|
50
|
+
declare function oxlintConfig(...overrides: OxlintConfig[]): OxlintOptions;
|
|
36
51
|
//#endregion
|
|
37
52
|
//#region src/oxfmt.d.ts
|
|
38
53
|
type OxfmtOptions = Parameters<typeof defineConfig$1>[0];
|
|
@@ -43,13 +58,25 @@ type OxfmtOptions = Parameters<typeof defineConfig$1>[0];
|
|
|
43
58
|
declare function oxfmtConfig(...overrides: OxfmtOptions[]): OxfmtOptions;
|
|
44
59
|
//#endregion
|
|
45
60
|
//#region src/tailwind.d.ts
|
|
46
|
-
type OxlintOptions = Parameters<typeof defineConfig>[0];
|
|
47
61
|
interface TailwindOptions {
|
|
48
62
|
/**
|
|
49
|
-
* Path to the Tailwind entry CSS
|
|
50
|
-
*
|
|
63
|
+
* Path to the Tailwind entry CSS, so the plugin can resolve class names.
|
|
64
|
+
* Required. In a monorepo, pass an array of glob → CSS mappings; the last
|
|
65
|
+
* matching entry wins, so end with a `'**'` catch-all.
|
|
66
|
+
*
|
|
67
|
+
* @example 'src/global.css'
|
|
68
|
+
* @example
|
|
69
|
+
* ```ts
|
|
70
|
+
* [
|
|
71
|
+
* { files: 'packages/ui/**', use: 'packages/ui/src/styles.css' },
|
|
72
|
+
* { files: '**', use: 'src/global.css' },
|
|
73
|
+
* ]
|
|
74
|
+
* ```
|
|
51
75
|
*/
|
|
52
|
-
entryPoint: string
|
|
76
|
+
entryPoint: string | {
|
|
77
|
+
files: string;
|
|
78
|
+
use: string;
|
|
79
|
+
}[];
|
|
53
80
|
/**
|
|
54
81
|
* Class names to exempt from `no-unknown-classes` — e.g. classes generated by
|
|
55
82
|
* component libraries that the plugin can't resolve from the entry CSS.
|
|
@@ -63,20 +90,19 @@ interface TailwindOptions {
|
|
|
63
90
|
cwd?: string;
|
|
64
91
|
}
|
|
65
92
|
/**
|
|
66
|
-
* Tailwind linting via [`
|
|
93
|
+
* Tailwind v4 linting via [`oxlint-tailwindcss`](https://github.com/sergioazoc/oxlint-tailwindcss).
|
|
67
94
|
* Pass the result as an argument to `oxlintConfig`:
|
|
68
95
|
*
|
|
69
96
|
* ```ts
|
|
70
|
-
* export default oxlintConfig(
|
|
97
|
+
* export default oxlintConfig(tailwindPlugin({
|
|
71
98
|
* entryPoint: 'app/globals.css',
|
|
72
99
|
* ignoreClasses: ['toaster'],
|
|
73
100
|
* }))
|
|
74
101
|
* ```
|
|
75
102
|
*
|
|
76
103
|
* The plugin is an optional peer dependency — install it yourself
|
|
77
|
-
* (`pnpm add -D
|
|
78
|
-
* is thrown.
|
|
104
|
+
* (`pnpm add -D oxlint-tailwindcss`). If it is missing, an error is thrown.
|
|
79
105
|
*/
|
|
80
|
-
declare function
|
|
106
|
+
declare function tailwindPlugin({ entryPoint, ignoreClasses, cwd }: TailwindOptions): OxlintConfig;
|
|
81
107
|
//#endregion
|
|
82
|
-
export { oxfmtConfig, oxlintConfig,
|
|
108
|
+
export { oxfmtConfig, oxlintConfig, tailwindPlugin };
|
package/dist/index.mjs
CHANGED
|
@@ -536,8 +536,9 @@ function resolvePlugins(cwd) {
|
|
|
536
536
|
* plugin whose dependency lives elsewhere — e.g. a nested workspace like
|
|
537
537
|
* `apps/web/package.json` — add it through `plugins`.
|
|
538
538
|
*
|
|
539
|
-
* Pass any number of config objects; they are deep-merged (arrays concatenated
|
|
540
|
-
* so pieces like {@link
|
|
539
|
+
* Pass any number of config objects; they are deep-merged (arrays concatenated,
|
|
540
|
+
* with `plugins` de-duplicated), so pieces like {@link tailwindPlugin} compose
|
|
541
|
+
* without clobbering each other.
|
|
541
542
|
*
|
|
542
543
|
* @example
|
|
543
544
|
* ```ts
|
|
@@ -554,12 +555,14 @@ function resolvePlugins(cwd) {
|
|
|
554
555
|
* // compose Tailwind — its plugins merge with the ones above, not overwrite
|
|
555
556
|
* export default oxlintConfig(
|
|
556
557
|
* { plugins: ['react', 'jsx-a11y'] },
|
|
557
|
-
*
|
|
558
|
+
* tailwindPlugin({ entryPoint: 'app/globals.css' }),
|
|
558
559
|
* )
|
|
559
560
|
* ```
|
|
560
561
|
*/
|
|
561
562
|
function oxlintConfig(...overrides) {
|
|
562
|
-
|
|
563
|
+
const merged = defu({}, ...overrides, { plugins: resolvePlugins(process.cwd()) }, baseOxlintConfig);
|
|
564
|
+
if (merged?.plugins) merged.plugins = [...new Set(merged.plugins)];
|
|
565
|
+
return merged;
|
|
563
566
|
}
|
|
564
567
|
//#endregion
|
|
565
568
|
//#region src/oxfmt.ts
|
|
@@ -580,38 +583,40 @@ function oxfmtConfig(...overrides) {
|
|
|
580
583
|
}
|
|
581
584
|
//#endregion
|
|
582
585
|
//#region src/tailwind.ts
|
|
583
|
-
const TAILWIND_PLUGIN = "
|
|
586
|
+
const TAILWIND_PLUGIN = "oxlint-tailwindcss";
|
|
584
587
|
/**
|
|
585
|
-
* Tailwind linting via [`
|
|
588
|
+
* Tailwind v4 linting via [`oxlint-tailwindcss`](https://github.com/sergioazoc/oxlint-tailwindcss).
|
|
586
589
|
* Pass the result as an argument to `oxlintConfig`:
|
|
587
590
|
*
|
|
588
591
|
* ```ts
|
|
589
|
-
* export default oxlintConfig(
|
|
592
|
+
* export default oxlintConfig(tailwindPlugin({
|
|
590
593
|
* entryPoint: 'app/globals.css',
|
|
591
594
|
* ignoreClasses: ['toaster'],
|
|
592
595
|
* }))
|
|
593
596
|
* ```
|
|
594
597
|
*
|
|
595
598
|
* The plugin is an optional peer dependency — install it yourself
|
|
596
|
-
* (`pnpm add -D
|
|
597
|
-
* is thrown.
|
|
599
|
+
* (`pnpm add -D oxlint-tailwindcss`). If it is missing, an error is thrown.
|
|
598
600
|
*/
|
|
599
|
-
function
|
|
601
|
+
function tailwindPlugin({ entryPoint, ignoreClasses = [], cwd = process.cwd() }) {
|
|
600
602
|
if (!getInstalledPackages(cwd).has(TAILWIND_PLUGIN)) throw new Error(`[@letstri/oxc-config] Tailwind linting needs "${TAILWIND_PLUGIN}". Install it: pnpm add -D ${TAILWIND_PLUGIN}`);
|
|
601
603
|
return defineConfig({
|
|
602
604
|
jsPlugins: [TAILWIND_PLUGIN],
|
|
603
|
-
settings: {
|
|
605
|
+
settings: { tailwindcss: { entryPoint } },
|
|
604
606
|
rules: {
|
|
605
|
-
"
|
|
606
|
-
"
|
|
607
|
-
"
|
|
608
|
-
"
|
|
609
|
-
"
|
|
610
|
-
"
|
|
611
|
-
"
|
|
612
|
-
"
|
|
607
|
+
"tailwindcss/enforce-sort-order": "error",
|
|
608
|
+
"tailwindcss/enforce-consistent-line-wrapping": "off",
|
|
609
|
+
"tailwindcss/no-unnecessary-whitespace": "off",
|
|
610
|
+
"tailwindcss/enforce-canonical": "error",
|
|
611
|
+
"tailwindcss/consistent-variant-order": "error",
|
|
612
|
+
"tailwindcss/enforce-consistent-important-position": "error",
|
|
613
|
+
"tailwindcss/no-conflicting-classes": "error",
|
|
614
|
+
"tailwindcss/no-deprecated-classes": "error",
|
|
615
|
+
"tailwindcss/no-duplicate-classes": "error",
|
|
616
|
+
"tailwindcss/no-unnecessary-arbitrary-value": "warn",
|
|
617
|
+
"tailwindcss/no-unknown-classes": ["error", { allowlist: ignoreClasses }]
|
|
613
618
|
}
|
|
614
619
|
});
|
|
615
620
|
}
|
|
616
621
|
//#endregion
|
|
617
|
-
export { oxfmtConfig, oxlintConfig,
|
|
622
|
+
export { oxfmtConfig, oxlintConfig, tailwindPlugin };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@letstri/oxc-config",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Opinionated Oxlint and Oxfmt configs",
|
|
5
5
|
"homepage": "https://github.com/letstri/oxc-config#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -46,12 +46,12 @@
|
|
|
46
46
|
"typescript": "^6.0.3"
|
|
47
47
|
},
|
|
48
48
|
"peerDependencies": {
|
|
49
|
-
"eslint-plugin-better-tailwindcss": ">=4",
|
|
50
49
|
"oxfmt": ">=0.58.0",
|
|
51
|
-
"oxlint": ">=1.73.0"
|
|
50
|
+
"oxlint": ">=1.73.0",
|
|
51
|
+
"oxlint-tailwindcss": ">=1"
|
|
52
52
|
},
|
|
53
53
|
"peerDependenciesMeta": {
|
|
54
|
-
"
|
|
54
|
+
"oxlint-tailwindcss": {
|
|
55
55
|
"optional": true
|
|
56
56
|
}
|
|
57
57
|
},
|