@letstri/oxc-config 0.2.1 → 0.4.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 +58 -125
- package/dist/cli.d.mts +1 -0
- package/dist/cli.mjs +165 -0
- package/dist/index.d.mts +26 -8
- package/dist/index.mjs +25 -11
- package/package.json +7 -2
package/README.md
CHANGED
|
@@ -4,15 +4,25 @@ Opinionated, shared [oxlint](https://oxc.rs/docs/guide/usage/linter.html) and [o
|
|
|
4
4
|
|
|
5
5
|
> [!NOTE]
|
|
6
6
|
> This is an **opinionated** config — it ships a curated set of rules and
|
|
7
|
-
> formatting defaults meant to work out of the box. Override
|
|
8
|
-
> disagree with
|
|
7
|
+
> formatting defaults meant to work out of the box. [Override](#overrides)
|
|
8
|
+
> anything you disagree with.
|
|
9
9
|
|
|
10
10
|
## Install
|
|
11
11
|
|
|
12
12
|
```bash
|
|
13
|
-
|
|
13
|
+
npm i -D @letstri/oxc-config oxlint oxfmt
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
+
Then scaffold the config files and editor settings with the `oxc-config` CLI:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npx oxc-config config # create oxlint.config.ts + oxfmt.config.ts
|
|
20
|
+
npx oxc-config editors # write .vscode + .zed settings
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Run `oxc-config --help` for all commands. Details: [Usage](#usage) and
|
|
24
|
+
[Editor setup](#editor-setup).
|
|
25
|
+
|
|
16
26
|
## AI setup prompt
|
|
17
27
|
|
|
18
28
|
Paste this into Claude Code, Cursor, or any coding agent to wire everything up:
|
|
@@ -44,7 +54,7 @@ Set up @letstri/oxc-config (oxlint + oxfmt) in this project:
|
|
|
44
54
|
- "format:check": "oxfmt --check"
|
|
45
55
|
6. Framework plugins auto-enable from the nearest package.json. If a framework
|
|
46
56
|
dep (react/vue/next/vitest/jest/typescript) lives in a nested workspace,
|
|
47
|
-
enable it manually, e.g. `oxlintConfig({
|
|
57
|
+
enable it manually, e.g. `oxlintConfig({ plugins: ['vue'] })`.
|
|
48
58
|
7. Add the VS Code and Zed editor settings from the @letstri/oxc-config README.
|
|
49
59
|
8. Run `pnpm lint` and `pnpm format` and fix anything reported.
|
|
50
60
|
````
|
|
@@ -96,33 +106,45 @@ export default oxlintConfig({
|
|
|
96
106
|
|
|
97
107
|
### Overrides
|
|
98
108
|
|
|
99
|
-
|
|
100
|
-
config via [defu](https://github.com/unjs/defu)
|
|
109
|
+
`oxlintConfig` / `oxfmtConfig` accept **any number of config objects**, all
|
|
110
|
+
deep-merged over the base config via [defu](https://github.com/unjs/defu) (arrays
|
|
111
|
+
are concatenated, so plugins from different pieces combine instead of
|
|
112
|
+
overwriting):
|
|
101
113
|
|
|
102
114
|
```ts
|
|
103
|
-
export default oxlintConfig({
|
|
104
|
-
rules: {
|
|
105
|
-
'no-console': 'off',
|
|
106
|
-
},
|
|
107
|
-
})
|
|
115
|
+
export default oxlintConfig({ rules: { 'no-console': 'off' } }, { plugins: ['vue'] })
|
|
108
116
|
```
|
|
109
117
|
|
|
110
118
|
### Tailwind
|
|
111
119
|
|
|
112
120
|
`tailwind({ entryPoint })` returns a config chunk for
|
|
113
121
|
[`eslint-plugin-better-tailwindcss`](https://github.com/schoero/eslint-plugin-better-tailwindcss).
|
|
114
|
-
|
|
122
|
+
Pass it as an argument to `oxlintConfig`:
|
|
115
123
|
|
|
116
124
|
```ts
|
|
117
125
|
import { oxlintConfig, tailwind } from '@letstri/oxc-config'
|
|
118
126
|
|
|
119
|
-
export default oxlintConfig(
|
|
120
|
-
|
|
121
|
-
})
|
|
127
|
+
export default oxlintConfig(
|
|
128
|
+
{ plugins: ['react', 'jsx-a11y'] },
|
|
129
|
+
tailwind({ entryPoint: 'app/globals.css' }),
|
|
130
|
+
)
|
|
122
131
|
```
|
|
123
132
|
|
|
124
|
-
|
|
125
|
-
|
|
133
|
+
Because arguments are merged (not spread), Tailwind's plugins combine with the
|
|
134
|
+
ones above rather than overwriting them.
|
|
135
|
+
|
|
136
|
+
Options:
|
|
137
|
+
|
|
138
|
+
- `entryPoint` (required) — your Tailwind entry CSS, so the plugin can resolve
|
|
139
|
+
class names.
|
|
140
|
+
- `ignoreClasses` — class names to exempt from `no-unknown-classes` (e.g. classes
|
|
141
|
+
a component library generates that the plugin can't resolve):
|
|
142
|
+
|
|
143
|
+
```ts
|
|
144
|
+
tailwind({ entryPoint: 'app/globals.css', ignoreClasses: ['toaster'] })
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
The plugin is an **optional peer dependency** — install it yourself:
|
|
126
148
|
|
|
127
149
|
```bash
|
|
128
150
|
pnpm add -D eslint-plugin-better-tailwindcss
|
|
@@ -135,119 +157,30 @@ If the plugin is missing, `tailwind()` throws with an install hint.
|
|
|
135
157
|
Both editors use the official [oxc](https://oxc.rs) tooling — `oxlint` for
|
|
136
158
|
linting and `oxfmt` for formatting — replacing ESLint and Prettier.
|
|
137
159
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
Install the [`oxc.oxc-vscode`](https://marketplace.visualstudio.com/items?itemName=oxc.oxc-vscode)
|
|
141
|
-
extension.
|
|
142
|
-
|
|
143
|
-
<details>
|
|
144
|
-
<summary>Show VS Code config</summary>
|
|
145
|
-
|
|
146
|
-
`.vscode/extensions.json`:
|
|
160
|
+
The `oxc-config editors` command writes (or updates) the editor configs for you,
|
|
161
|
+
deep-merging into any existing files so your other settings are kept:
|
|
147
162
|
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
}
|
|
152
|
-
```
|
|
163
|
+
```bash
|
|
164
|
+
# both editors
|
|
165
|
+
pnpm exec oxc-config editors
|
|
153
166
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
{
|
|
158
|
-
"oxc.configPath": "oxlint.config.ts",
|
|
159
|
-
"oxc.fmt.configPath": "oxfmt.config.ts",
|
|
160
|
-
"oxc.typeAware": true,
|
|
161
|
-
"oxc.unusedDisableDirectives": "deny",
|
|
162
|
-
"oxc.enable": true,
|
|
163
|
-
"prettier.enable": false,
|
|
164
|
-
"editor.defaultFormatter": "oxc.oxc-vscode",
|
|
165
|
-
"editor.formatOnSave": true,
|
|
166
|
-
"editor.formatOnSaveMode": "file", // oxfmt can only format whole files
|
|
167
|
-
"editor.codeActionsOnSave": {
|
|
168
|
-
"source.fixAll.oxc": "explicit",
|
|
169
|
-
"source.organizeImports": "never", // let oxfmt handle import organization
|
|
170
|
-
},
|
|
171
|
-
}
|
|
167
|
+
# or just one
|
|
168
|
+
pnpm exec oxc-config editors --vscode
|
|
169
|
+
pnpm exec oxc-config editors --zed
|
|
172
170
|
```
|
|
173
171
|
|
|
174
|
-
|
|
172
|
+
It's idempotent — safe to re-run to pull the latest recommended settings.
|
|
175
173
|
|
|
176
|
-
###
|
|
177
|
-
|
|
178
|
-
Zed ships with the oxc language servers built in.
|
|
174
|
+
### VS Code
|
|
179
175
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
```jsonc
|
|
186
|
-
{
|
|
187
|
-
"lsp": {
|
|
188
|
-
"oxlint": {
|
|
189
|
-
"initialization_options": {
|
|
190
|
-
"settings": {
|
|
191
|
-
"configPath": null,
|
|
192
|
-
"run": "onType",
|
|
193
|
-
"disableNestedConfig": false,
|
|
194
|
-
"fixKind": "safe_fix",
|
|
195
|
-
"unusedDisableDirectives": "deny",
|
|
196
|
-
},
|
|
197
|
-
},
|
|
198
|
-
},
|
|
199
|
-
"oxfmt": {
|
|
200
|
-
"initialization_options": {
|
|
201
|
-
"settings": {
|
|
202
|
-
"fmt.configPath": null,
|
|
203
|
-
"run": "onSave",
|
|
204
|
-
},
|
|
205
|
-
},
|
|
206
|
-
},
|
|
207
|
-
},
|
|
208
|
-
"languages": {
|
|
209
|
-
"TypeScript": {
|
|
210
|
-
"format_on_save": "on",
|
|
211
|
-
"prettier": { "allowed": false },
|
|
212
|
-
"language_servers": ["...", "oxlint", "oxfmt"],
|
|
213
|
-
"formatter": [
|
|
214
|
-
{ "language_server": { "name": "oxfmt" } },
|
|
215
|
-
{ "code_action": "source.fixAll.oxc" },
|
|
216
|
-
],
|
|
217
|
-
},
|
|
218
|
-
"TSX": {
|
|
219
|
-
"format_on_save": "on",
|
|
220
|
-
"prettier": { "allowed": false },
|
|
221
|
-
"language_servers": ["...", "oxlint", "oxfmt"],
|
|
222
|
-
"formatter": [
|
|
223
|
-
{ "language_server": { "name": "oxfmt" } },
|
|
224
|
-
{ "code_action": "source.fixAll.oxc" },
|
|
225
|
-
],
|
|
226
|
-
},
|
|
227
|
-
"JavaScript": {
|
|
228
|
-
"format_on_save": "on",
|
|
229
|
-
"prettier": { "allowed": false },
|
|
230
|
-
"language_servers": ["...", "oxlint", "oxfmt"],
|
|
231
|
-
"formatter": [
|
|
232
|
-
{ "language_server": { "name": "oxfmt" } },
|
|
233
|
-
{ "code_action": "source.fixAll.oxc" },
|
|
234
|
-
],
|
|
235
|
-
},
|
|
236
|
-
"JSON": {
|
|
237
|
-
"format_on_save": "on",
|
|
238
|
-
"prettier": { "allowed": false },
|
|
239
|
-
"formatter": [{ "language_server": { "name": "oxfmt" } }],
|
|
240
|
-
},
|
|
241
|
-
"Markdown": {
|
|
242
|
-
"format_on_save": "on",
|
|
243
|
-
"prettier": { "allowed": false },
|
|
244
|
-
"formatter": [{ "language_server": { "name": "oxfmt" } }],
|
|
245
|
-
},
|
|
246
|
-
},
|
|
247
|
-
}
|
|
248
|
-
```
|
|
176
|
+
Install the [`oxc.oxc-vscode`](https://marketplace.visualstudio.com/items?itemName=oxc.oxc-vscode)
|
|
177
|
+
extension (`oxc-config editors --vscode` also adds it to `.vscode/extensions.json`). The
|
|
178
|
+
CLI writes `.vscode/settings.json` — oxlint as linter, oxfmt as the default
|
|
179
|
+
formatter with format-on-save, and Prettier's import organization turned off.
|
|
249
180
|
|
|
250
|
-
|
|
251
|
-
format (`JSONC`, `CSS`, `HTML`, `YAML`, …).
|
|
181
|
+
### Zed
|
|
252
182
|
|
|
253
|
-
|
|
183
|
+
Zed ships with the oxc language servers built in, so no extension is needed.
|
|
184
|
+
`oxc-config editors --zed` writes `.zed/settings.json` — oxfmt as the formatter (with
|
|
185
|
+
`source.fixAll.oxc` on save for JS/TS) and Prettier disabled, across the file
|
|
186
|
+
types oxfmt supports.
|
package/dist/cli.d.mts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
package/dist/cli.mjs
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import process from "node:process";
|
|
3
|
+
import { createDefu } from "defu";
|
|
4
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
5
|
+
import { dirname, resolve } from "node:path";
|
|
6
|
+
import { boolean, command, run } from "@drizzle-team/brocli";
|
|
7
|
+
import { parse } from "jsonc-parser";
|
|
8
|
+
//#region src/editors.ts
|
|
9
|
+
/**
|
|
10
|
+
* Editor config templates, adapted from the official oxc examples:
|
|
11
|
+
* - https://github.com/oxc-project/oxc-vscode/blob/main/.vscode/settings.json
|
|
12
|
+
* - https://github.com/oxc-project/oxc-zed/blob/main/examples/both/.zed/settings.json
|
|
13
|
+
*
|
|
14
|
+
* `configPath` values point at this library's TypeScript config files.
|
|
15
|
+
*/
|
|
16
|
+
const vscodeExtensions = { recommendations: ["oxc.oxc-vscode"] };
|
|
17
|
+
const vscodeSettings = {
|
|
18
|
+
"oxc.configPath": "oxlint.config.ts",
|
|
19
|
+
"oxc.fmt.configPath": "oxfmt.config.ts",
|
|
20
|
+
"oxc.typeAware": true,
|
|
21
|
+
"oxc.unusedDisableDirectives": "deny",
|
|
22
|
+
"editor.defaultFormatter": "oxc.oxc-vscode",
|
|
23
|
+
"editor.formatOnSave": true,
|
|
24
|
+
"editor.formatOnSaveMode": "file",
|
|
25
|
+
"editor.codeActionsOnSave": { "source.organizeImports": "never" }
|
|
26
|
+
};
|
|
27
|
+
const oxfmtFormatter = { language_server: { name: "oxfmt" } };
|
|
28
|
+
function formatOnSave(withFix = false) {
|
|
29
|
+
return {
|
|
30
|
+
format_on_save: "on",
|
|
31
|
+
prettier: { allowed: false },
|
|
32
|
+
formatter: withFix ? [oxfmtFormatter, { code_action: "source.fixAll.oxc" }] : [oxfmtFormatter]
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
const cssLike = [
|
|
36
|
+
"CSS",
|
|
37
|
+
"GraphQL",
|
|
38
|
+
"Handlebars",
|
|
39
|
+
"HTML",
|
|
40
|
+
"JSON",
|
|
41
|
+
"JSON5",
|
|
42
|
+
"JSONC",
|
|
43
|
+
"Less",
|
|
44
|
+
"Markdown",
|
|
45
|
+
"MDX",
|
|
46
|
+
"SCSS",
|
|
47
|
+
"YAML"
|
|
48
|
+
];
|
|
49
|
+
const codeLike = [
|
|
50
|
+
"JavaScript",
|
|
51
|
+
"TypeScript",
|
|
52
|
+
"TSX",
|
|
53
|
+
"Vue.js"
|
|
54
|
+
];
|
|
55
|
+
const zedSettings = {
|
|
56
|
+
lsp: {
|
|
57
|
+
oxlint: { initialization_options: { settings: {
|
|
58
|
+
configPath: null,
|
|
59
|
+
run: "onType",
|
|
60
|
+
disableNestedConfig: false,
|
|
61
|
+
fixKind: "safe_fix",
|
|
62
|
+
unusedDisableDirectives: "deny"
|
|
63
|
+
} } },
|
|
64
|
+
oxfmt: { initialization_options: { settings: {
|
|
65
|
+
"fmt.configPath": null,
|
|
66
|
+
"run": "onSave"
|
|
67
|
+
} } }
|
|
68
|
+
},
|
|
69
|
+
languages: {
|
|
70
|
+
...Object.fromEntries(cssLike.map((lang) => [lang, formatOnSave()])),
|
|
71
|
+
...Object.fromEntries(codeLike.map((lang) => [lang, formatOnSave(true)]))
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
//#endregion
|
|
75
|
+
//#region src/cli.ts
|
|
76
|
+
/**
|
|
77
|
+
* Like defu, but arrays are merged as a de-duplicated union instead of being
|
|
78
|
+
* concatenated — keeps updates idempotent and preserves user-added entries.
|
|
79
|
+
*/
|
|
80
|
+
const mergeConfig = createDefu((obj, key, value) => {
|
|
81
|
+
const current = obj[key];
|
|
82
|
+
if (Array.isArray(current) && Array.isArray(value)) {
|
|
83
|
+
const seen = /* @__PURE__ */ new Set();
|
|
84
|
+
obj[key] = [...value, ...current].filter((item) => {
|
|
85
|
+
const id = JSON.stringify(item);
|
|
86
|
+
if (seen.has(id)) return false;
|
|
87
|
+
seen.add(id);
|
|
88
|
+
return true;
|
|
89
|
+
});
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
return false;
|
|
93
|
+
});
|
|
94
|
+
function readJsonc(path) {
|
|
95
|
+
if (!existsSync(path)) return {};
|
|
96
|
+
return parse(readFileSync(path, "utf-8"), [], { allowTrailingComma: true }) ?? {};
|
|
97
|
+
}
|
|
98
|
+
/** Deep-merge `base` into the JSON(C) file at `path`, creating it if absent. */
|
|
99
|
+
function mergeJsonFile(path, base) {
|
|
100
|
+
const existed = existsSync(path);
|
|
101
|
+
const merged = mergeConfig(base, readJsonc(path));
|
|
102
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
103
|
+
writeFileSync(path, `${JSON.stringify(merged, null, 2)}\n`);
|
|
104
|
+
return existed ? "updated" : "created";
|
|
105
|
+
}
|
|
106
|
+
/** Write `content` to `path`, skipping an existing file unless `force`. */
|
|
107
|
+
function writeFile(path, content, force) {
|
|
108
|
+
const existed = existsSync(path);
|
|
109
|
+
if (existed && !force) return "skipped";
|
|
110
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
111
|
+
writeFileSync(path, content);
|
|
112
|
+
return existed ? "overwritten" : "created";
|
|
113
|
+
}
|
|
114
|
+
const OXLINT_CONFIG = `import { oxlintConfig } from '@letstri/oxc-config'
|
|
115
|
+
|
|
116
|
+
export default oxlintConfig()
|
|
117
|
+
`;
|
|
118
|
+
const OXFMT_CONFIG = `import { oxfmtConfig } from '@letstri/oxc-config'
|
|
119
|
+
|
|
120
|
+
export default oxfmtConfig()
|
|
121
|
+
`;
|
|
122
|
+
function version() {
|
|
123
|
+
try {
|
|
124
|
+
return JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf-8")).version ?? "0.0.0";
|
|
125
|
+
} catch {
|
|
126
|
+
return "0.0.0";
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
run([command({
|
|
130
|
+
name: "config",
|
|
131
|
+
desc: "Create oxlint.config.ts and oxfmt.config.ts",
|
|
132
|
+
options: { force: boolean().alias("f").desc("Overwrite existing files").default(false) },
|
|
133
|
+
handler: ({ force }) => {
|
|
134
|
+
const cwd = process.cwd();
|
|
135
|
+
const lint = writeFile(resolve(cwd, "oxlint.config.ts"), OXLINT_CONFIG, force);
|
|
136
|
+
const fmt = writeFile(resolve(cwd, "oxfmt.config.ts"), OXFMT_CONFIG, force);
|
|
137
|
+
process.stdout.write(`config: ${lint} oxlint.config.ts, ${fmt} oxfmt.config.ts\n`);
|
|
138
|
+
}
|
|
139
|
+
}), command({
|
|
140
|
+
name: "editors",
|
|
141
|
+
desc: "Write/update VS Code and Zed editor configs (deep-merged into existing files)",
|
|
142
|
+
options: {
|
|
143
|
+
vscode: boolean().desc("Only VS Code").default(false),
|
|
144
|
+
zed: boolean().desc("Only Zed").default(false)
|
|
145
|
+
},
|
|
146
|
+
handler: ({ vscode, zed }) => {
|
|
147
|
+
const both = !vscode && !zed;
|
|
148
|
+
const cwd = process.cwd();
|
|
149
|
+
if (both || vscode) {
|
|
150
|
+
const s = mergeJsonFile(resolve(cwd, ".vscode/settings.json"), vscodeSettings);
|
|
151
|
+
const e = mergeJsonFile(resolve(cwd, ".vscode/extensions.json"), vscodeExtensions);
|
|
152
|
+
process.stdout.write(`vscode: ${s} .vscode/settings.json, ${e} .vscode/extensions.json\n`);
|
|
153
|
+
}
|
|
154
|
+
if (both || zed) {
|
|
155
|
+
const s = mergeJsonFile(resolve(cwd, ".zed/settings.json"), zedSettings);
|
|
156
|
+
process.stdout.write(`zed: ${s} .zed/settings.json\n`);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
})], {
|
|
160
|
+
name: "oxc-config",
|
|
161
|
+
description: "Set up @letstri/oxc-config in your project",
|
|
162
|
+
version: version()
|
|
163
|
+
});
|
|
164
|
+
//#endregion
|
|
165
|
+
export {};
|
package/dist/index.d.mts
CHANGED
|
@@ -8,7 +8,10 @@ type OxlintOptions$1 = Parameters<typeof defineConfig>[0];
|
|
|
8
8
|
* Plugins are auto-enabled by detecting their package (`typescript`, `react`,
|
|
9
9
|
* `vue`, `next`, `vitest`, `jest`) in the nearest `package.json`. To enable a
|
|
10
10
|
* plugin whose dependency lives elsewhere — e.g. a nested workspace like
|
|
11
|
-
* `apps/web/package.json` — add it through `
|
|
11
|
+
* `apps/web/package.json` — add it through `plugins`.
|
|
12
|
+
*
|
|
13
|
+
* Pass any number of config objects; they are deep-merged (arrays concatenated),
|
|
14
|
+
* so pieces like {@link tailwind} compose without clobbering each other.
|
|
12
15
|
*
|
|
13
16
|
* @example
|
|
14
17
|
* ```ts
|
|
@@ -22,15 +25,22 @@ type OxlintOptions$1 = Parameters<typeof defineConfig>[0];
|
|
|
22
25
|
* ```
|
|
23
26
|
* @example
|
|
24
27
|
* ```ts
|
|
25
|
-
* //
|
|
26
|
-
* export default oxlintConfig(
|
|
28
|
+
* // compose Tailwind — its plugins merge with the ones above, not overwrite
|
|
29
|
+
* export default oxlintConfig(
|
|
30
|
+
* { plugins: ['react', 'jsx-a11y'] },
|
|
31
|
+
* tailwind({ entryPoint: 'app/globals.css' }),
|
|
32
|
+
* )
|
|
27
33
|
* ```
|
|
28
34
|
*/
|
|
29
|
-
declare function oxlintConfig(overrides
|
|
35
|
+
declare function oxlintConfig(...overrides: OxlintOptions$1[]): OxlintOptions$1;
|
|
30
36
|
//#endregion
|
|
31
37
|
//#region src/oxfmt.d.ts
|
|
32
38
|
type OxfmtOptions = Parameters<typeof defineConfig$1>[0];
|
|
33
|
-
|
|
39
|
+
/**
|
|
40
|
+
* Build an oxfmt config. Pass any number of config objects; they are deep-merged
|
|
41
|
+
* over the base config via defu.
|
|
42
|
+
*/
|
|
43
|
+
declare function oxfmtConfig(...overrides: OxfmtOptions[]): OxfmtOptions;
|
|
34
44
|
//#endregion
|
|
35
45
|
//#region src/tailwind.d.ts
|
|
36
46
|
type OxlintOptions = Parameters<typeof defineConfig>[0];
|
|
@@ -40,6 +50,11 @@ interface TailwindOptions {
|
|
|
40
50
|
* class names.
|
|
41
51
|
*/
|
|
42
52
|
entryPoint: string;
|
|
53
|
+
/**
|
|
54
|
+
* Class names to exempt from `no-unknown-classes` — e.g. classes generated by
|
|
55
|
+
* component libraries that the plugin can't resolve from the entry CSS.
|
|
56
|
+
*/
|
|
57
|
+
ignoreClasses?: string[];
|
|
43
58
|
/**
|
|
44
59
|
* Directory scanned to check the plugin is installed.
|
|
45
60
|
*
|
|
@@ -49,16 +64,19 @@ interface TailwindOptions {
|
|
|
49
64
|
}
|
|
50
65
|
/**
|
|
51
66
|
* Tailwind linting via [`eslint-plugin-better-tailwindcss`](https://github.com/schoero/eslint-plugin-better-tailwindcss).
|
|
52
|
-
*
|
|
67
|
+
* Pass the result as an argument to `oxlintConfig`:
|
|
53
68
|
*
|
|
54
69
|
* ```ts
|
|
55
|
-
* export default oxlintConfig(
|
|
70
|
+
* export default oxlintConfig(tailwind({
|
|
71
|
+
* entryPoint: 'app/globals.css',
|
|
72
|
+
* ignoreClasses: ['toaster'],
|
|
73
|
+
* }))
|
|
56
74
|
* ```
|
|
57
75
|
*
|
|
58
76
|
* The plugin is an optional peer dependency — install it yourself
|
|
59
77
|
* (`pnpm add -D eslint-plugin-better-tailwindcss`). If it is missing, an error
|
|
60
78
|
* is thrown.
|
|
61
79
|
*/
|
|
62
|
-
declare function tailwind({ entryPoint, cwd }: TailwindOptions): OxlintOptions;
|
|
80
|
+
declare function tailwind({ entryPoint, ignoreClasses, cwd }: TailwindOptions): OxlintOptions;
|
|
63
81
|
//#endregion
|
|
64
82
|
export { oxfmtConfig, oxlintConfig, tailwind };
|
package/dist/index.mjs
CHANGED
|
@@ -534,7 +534,10 @@ function resolvePlugins(cwd) {
|
|
|
534
534
|
* Plugins are auto-enabled by detecting their package (`typescript`, `react`,
|
|
535
535
|
* `vue`, `next`, `vitest`, `jest`) in the nearest `package.json`. To enable a
|
|
536
536
|
* plugin whose dependency lives elsewhere — e.g. a nested workspace like
|
|
537
|
-
* `apps/web/package.json` — add it through `
|
|
537
|
+
* `apps/web/package.json` — add it through `plugins`.
|
|
538
|
+
*
|
|
539
|
+
* Pass any number of config objects; they are deep-merged (arrays concatenated),
|
|
540
|
+
* so pieces like {@link tailwind} compose without clobbering each other.
|
|
538
541
|
*
|
|
539
542
|
* @example
|
|
540
543
|
* ```ts
|
|
@@ -548,41 +551,52 @@ function resolvePlugins(cwd) {
|
|
|
548
551
|
* ```
|
|
549
552
|
* @example
|
|
550
553
|
* ```ts
|
|
551
|
-
* //
|
|
552
|
-
* export default oxlintConfig(
|
|
554
|
+
* // compose Tailwind — its plugins merge with the ones above, not overwrite
|
|
555
|
+
* export default oxlintConfig(
|
|
556
|
+
* { plugins: ['react', 'jsx-a11y'] },
|
|
557
|
+
* tailwind({ entryPoint: 'app/globals.css' }),
|
|
558
|
+
* )
|
|
553
559
|
* ```
|
|
554
560
|
*/
|
|
555
|
-
function oxlintConfig(overrides
|
|
556
|
-
return defu(overrides, { plugins: resolvePlugins(process.cwd()) }, baseOxlintConfig);
|
|
561
|
+
function oxlintConfig(...overrides) {
|
|
562
|
+
return defu({}, ...overrides, { plugins: resolvePlugins(process.cwd()) }, baseOxlintConfig);
|
|
557
563
|
}
|
|
558
564
|
//#endregion
|
|
559
565
|
//#region src/oxfmt.ts
|
|
560
566
|
const baseOxfmtConfig = defineConfig$1({
|
|
567
|
+
printWidth: 100,
|
|
561
568
|
singleQuote: true,
|
|
562
569
|
semi: false,
|
|
563
570
|
arrowParens: "avoid",
|
|
564
571
|
sortImports: true,
|
|
565
572
|
quoteProps: "consistent"
|
|
566
573
|
});
|
|
567
|
-
|
|
568
|
-
|
|
574
|
+
/**
|
|
575
|
+
* Build an oxfmt config. Pass any number of config objects; they are deep-merged
|
|
576
|
+
* over the base config via defu.
|
|
577
|
+
*/
|
|
578
|
+
function oxfmtConfig(...overrides) {
|
|
579
|
+
return defu({}, ...overrides, baseOxfmtConfig);
|
|
569
580
|
}
|
|
570
581
|
//#endregion
|
|
571
582
|
//#region src/tailwind.ts
|
|
572
583
|
const TAILWIND_PLUGIN = "eslint-plugin-better-tailwindcss";
|
|
573
584
|
/**
|
|
574
585
|
* Tailwind linting via [`eslint-plugin-better-tailwindcss`](https://github.com/schoero/eslint-plugin-better-tailwindcss).
|
|
575
|
-
*
|
|
586
|
+
* Pass the result as an argument to `oxlintConfig`:
|
|
576
587
|
*
|
|
577
588
|
* ```ts
|
|
578
|
-
* export default oxlintConfig(
|
|
589
|
+
* export default oxlintConfig(tailwind({
|
|
590
|
+
* entryPoint: 'app/globals.css',
|
|
591
|
+
* ignoreClasses: ['toaster'],
|
|
592
|
+
* }))
|
|
579
593
|
* ```
|
|
580
594
|
*
|
|
581
595
|
* The plugin is an optional peer dependency — install it yourself
|
|
582
596
|
* (`pnpm add -D eslint-plugin-better-tailwindcss`). If it is missing, an error
|
|
583
597
|
* is thrown.
|
|
584
598
|
*/
|
|
585
|
-
function tailwind({ entryPoint, cwd = process.cwd() }) {
|
|
599
|
+
function tailwind({ entryPoint, ignoreClasses = [], cwd = process.cwd() }) {
|
|
586
600
|
if (!getInstalledPackages(cwd).has(TAILWIND_PLUGIN)) throw new Error(`[@letstri/oxc-config] Tailwind linting needs "${TAILWIND_PLUGIN}". Install it: pnpm add -D ${TAILWIND_PLUGIN}`);
|
|
587
601
|
return defineConfig({
|
|
588
602
|
jsPlugins: [TAILWIND_PLUGIN],
|
|
@@ -595,7 +609,7 @@ function tailwind({ entryPoint, cwd = process.cwd() }) {
|
|
|
595
609
|
"better-tailwindcss/no-conflicting-classes": "error",
|
|
596
610
|
"better-tailwindcss/no-deprecated-classes": "error",
|
|
597
611
|
"better-tailwindcss/no-duplicate-classes": "error",
|
|
598
|
-
"better-tailwindcss/no-unknown-classes": "error"
|
|
612
|
+
"better-tailwindcss/no-unknown-classes": ["error", { ignore: ignoreClasses }]
|
|
599
613
|
}
|
|
600
614
|
});
|
|
601
615
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@letstri/oxc-config",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Opinionated Oxlint and Oxfmt configs",
|
|
5
5
|
"homepage": "https://github.com/letstri/oxc-config#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -12,6 +12,9 @@
|
|
|
12
12
|
"type": "git",
|
|
13
13
|
"url": "git+https://github.com/letstri/oxc-config.git"
|
|
14
14
|
},
|
|
15
|
+
"bin": {
|
|
16
|
+
"oxc-config": "./dist/cli.mjs"
|
|
17
|
+
},
|
|
15
18
|
"files": [
|
|
16
19
|
"dist"
|
|
17
20
|
],
|
|
@@ -28,7 +31,9 @@
|
|
|
28
31
|
"access": "public"
|
|
29
32
|
},
|
|
30
33
|
"dependencies": {
|
|
31
|
-
"
|
|
34
|
+
"@drizzle-team/brocli": "^0.12.0",
|
|
35
|
+
"defu": "^6.1.7",
|
|
36
|
+
"jsonc-parser": "^3.3.1"
|
|
32
37
|
},
|
|
33
38
|
"devDependencies": {
|
|
34
39
|
"@types/node": "^26.1.1",
|