@letstri/oxc-config 0.1.0 → 0.2.1
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 +38 -32
- package/dist/index.d.mts +55 -52
- package/dist/index.mjs +79 -64
- package/package.json +13 -16
package/README.md
CHANGED
|
@@ -71,59 +71,65 @@ export default oxfmtConfig()
|
|
|
71
71
|
|
|
72
72
|
### Plugins
|
|
73
73
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
74
|
+
Plugins are enabled automatically by detecting dependencies in the nearest
|
|
75
|
+
`package.json`:
|
|
76
|
+
|
|
77
|
+
| Dependency | Plugins enabled |
|
|
78
|
+
| ------------ | ------------------- |
|
|
79
|
+
| `typescript` | `typescript` |
|
|
80
|
+
| `react` | `react`, `jsx-a11y` |
|
|
81
|
+
| `vue` | `vue` |
|
|
82
|
+
| `next` | `nextjs` |
|
|
83
|
+
| `vitest` | `vitest` |
|
|
84
|
+
| `jest` | `jest` |
|
|
85
|
+
|
|
86
|
+
Detection only reads the **nearest** `package.json`. If a dependency isn't found
|
|
87
|
+
there — e.g. it lives in a nested workspace like `apps/web/package.json`, or is
|
|
88
|
+
hoisted somewhere the scan doesn't see — its plugin won't be enabled. Add it
|
|
89
|
+
manually via `plugins`:
|
|
78
90
|
|
|
79
91
|
```ts
|
|
80
92
|
export default oxlintConfig({
|
|
81
|
-
|
|
82
|
-
jest: false, // force off
|
|
93
|
+
plugins: ['vue'],
|
|
83
94
|
})
|
|
84
95
|
```
|
|
85
96
|
|
|
86
|
-
###
|
|
87
|
-
|
|
88
|
-
`tailwind: true` enables [`eslint-plugin-better-tailwindcss`](https://github.com/schoero/eslint-plugin-better-tailwindcss)
|
|
89
|
-
(auto-detected from a `tailwindcss` dependency). The plugin is an **optional peer
|
|
90
|
-
dependency** — install it yourself:
|
|
91
|
-
|
|
92
|
-
```bash
|
|
93
|
-
pnpm add -D eslint-plugin-better-tailwindcss
|
|
94
|
-
```
|
|
97
|
+
### Overrides
|
|
95
98
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
entry CSS so it can resolve class names:
|
|
99
|
+
Anything you pass to `oxlintConfig` / `oxfmtConfig` is deep-merged over the base
|
|
100
|
+
config via [defu](https://github.com/unjs/defu):
|
|
99
101
|
|
|
100
102
|
```ts
|
|
101
103
|
export default oxlintConfig({
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
settings: {
|
|
105
|
-
'better-tailwindcss': {
|
|
106
|
-
entryPoint: 'src/styles/globals.css',
|
|
107
|
-
},
|
|
108
|
-
},
|
|
104
|
+
rules: {
|
|
105
|
+
'no-console': 'off',
|
|
109
106
|
},
|
|
110
107
|
})
|
|
111
108
|
```
|
|
112
109
|
|
|
113
|
-
###
|
|
110
|
+
### Tailwind
|
|
114
111
|
|
|
115
|
-
`
|
|
112
|
+
`tailwind({ entryPoint })` returns a config chunk for
|
|
113
|
+
[`eslint-plugin-better-tailwindcss`](https://github.com/schoero/eslint-plugin-better-tailwindcss).
|
|
114
|
+
Spread it into `oxlintConfig`:
|
|
116
115
|
|
|
117
116
|
```ts
|
|
117
|
+
import { oxlintConfig, tailwind } from '@letstri/oxc-config'
|
|
118
|
+
|
|
118
119
|
export default oxlintConfig({
|
|
119
|
-
|
|
120
|
-
rules: {
|
|
121
|
-
'no-console': 'off',
|
|
122
|
-
},
|
|
123
|
-
},
|
|
120
|
+
...tailwind({ entryPoint: 'app/globals.css' }),
|
|
124
121
|
})
|
|
125
122
|
```
|
|
126
123
|
|
|
124
|
+
`entryPoint` (required) is your Tailwind entry CSS, so the plugin can resolve
|
|
125
|
+
class names. The plugin is an **optional peer dependency** — install it yourself:
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
pnpm add -D eslint-plugin-better-tailwindcss
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
If the plugin is missing, `tailwind()` throws with an install hint.
|
|
132
|
+
|
|
127
133
|
## Editor setup
|
|
128
134
|
|
|
129
135
|
Both editors use the official [oxc](https://oxc.rs) tooling — `oxlint` for
|
package/dist/index.d.mts
CHANGED
|
@@ -1,61 +1,64 @@
|
|
|
1
|
-
import { defineConfig } from "
|
|
2
|
-
import { defineConfig as defineConfig$1 } from "
|
|
3
|
-
//#region src/
|
|
4
|
-
type OxlintOptions = Parameters<typeof defineConfig
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
type
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
* The plugin is an optional peer dependency — install it yourself
|
|
39
|
-
* (`pnpm add -D eslint-plugin-better-tailwindcss`). If it is missing, a warning
|
|
40
|
-
* is logged and Tailwind linting is skipped. Point the plugin at your entry
|
|
41
|
-
* CSS via `override.settings`.
|
|
42
|
-
*/
|
|
43
|
-
tailwind?: boolean;
|
|
1
|
+
import { defineConfig } from "oxlint";
|
|
2
|
+
import { defineConfig as defineConfig$1 } from "oxfmt";
|
|
3
|
+
//#region src/oxlint.d.ts
|
|
4
|
+
type OxlintOptions$1 = Parameters<typeof defineConfig>[0];
|
|
5
|
+
/**
|
|
6
|
+
* Build an oxlint config.
|
|
7
|
+
*
|
|
8
|
+
* Plugins are auto-enabled by detecting their package (`typescript`, `react`,
|
|
9
|
+
* `vue`, `next`, `vitest`, `jest`) in the nearest `package.json`. To enable a
|
|
10
|
+
* plugin whose dependency lives elsewhere — e.g. a nested workspace like
|
|
11
|
+
* `apps/web/package.json` — add it through `overrides.plugins`.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```ts
|
|
15
|
+
* // auto-detect from the current package.json
|
|
16
|
+
* export default oxlintConfig()
|
|
17
|
+
* ```
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* // enable a plugin by hand, tweak a rule
|
|
21
|
+
* export default oxlintConfig({ plugins: ['vue'], rules: { 'no-console': 'off' } })
|
|
22
|
+
* ```
|
|
23
|
+
* @example
|
|
24
|
+
* ```ts
|
|
25
|
+
* // add Tailwind linting
|
|
26
|
+
* export default oxlintConfig({ ...tailwind({ entryPoint: 'app/globals.css' }) })
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
declare function oxlintConfig(overrides?: OxlintOptions$1): OxlintOptions$1;
|
|
30
|
+
//#endregion
|
|
31
|
+
//#region src/oxfmt.d.ts
|
|
32
|
+
type OxfmtOptions = Parameters<typeof defineConfig$1>[0];
|
|
33
|
+
declare function oxfmtConfig(overrides?: OxfmtOptions): OxfmtOptions;
|
|
34
|
+
//#endregion
|
|
35
|
+
//#region src/tailwind.d.ts
|
|
36
|
+
type OxlintOptions = Parameters<typeof defineConfig>[0];
|
|
37
|
+
interface TailwindOptions {
|
|
44
38
|
/**
|
|
45
|
-
*
|
|
39
|
+
* Path to the Tailwind entry CSS. Required — the plugin needs it to resolve
|
|
40
|
+
* class names.
|
|
46
41
|
*/
|
|
47
|
-
|
|
42
|
+
entryPoint: string;
|
|
48
43
|
/**
|
|
49
|
-
* Directory
|
|
44
|
+
* Directory scanned to check the plugin is installed.
|
|
50
45
|
*
|
|
51
46
|
* @default process.cwd()
|
|
52
47
|
*/
|
|
53
48
|
cwd?: string;
|
|
54
49
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
50
|
+
/**
|
|
51
|
+
* Tailwind linting via [`eslint-plugin-better-tailwindcss`](https://github.com/schoero/eslint-plugin-better-tailwindcss).
|
|
52
|
+
* Spread the result into `oxlintConfig`:
|
|
53
|
+
*
|
|
54
|
+
* ```ts
|
|
55
|
+
* export default oxlintConfig({ ...tailwind({ entryPoint: 'app/globals.css' }) })
|
|
56
|
+
* ```
|
|
57
|
+
*
|
|
58
|
+
* The plugin is an optional peer dependency — install it yourself
|
|
59
|
+
* (`pnpm add -D eslint-plugin-better-tailwindcss`). If it is missing, an error
|
|
60
|
+
* is thrown.
|
|
61
|
+
*/
|
|
62
|
+
declare function tailwind({ entryPoint, cwd }: TailwindOptions): OxlintOptions;
|
|
60
63
|
//#endregion
|
|
61
|
-
export { oxfmtConfig, oxlintConfig };
|
|
64
|
+
export { oxfmtConfig, oxlintConfig, tailwind };
|
package/dist/index.mjs
CHANGED
|
@@ -1,11 +1,25 @@
|
|
|
1
|
-
import { readFileSync } from "node:fs";
|
|
2
|
-
import { resolve } from "node:path";
|
|
3
1
|
import process from "node:process";
|
|
4
2
|
import { defu } from "defu";
|
|
5
|
-
import { defineConfig } from "
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
3
|
+
import { defineConfig } from "oxlint";
|
|
4
|
+
import { readFileSync } from "node:fs";
|
|
5
|
+
import { resolve } from "node:path";
|
|
6
|
+
import { defineConfig as defineConfig$1 } from "oxfmt";
|
|
7
|
+
//#region src/utils.ts
|
|
8
|
+
function getInstalledPackages(cwd) {
|
|
9
|
+
const names = /* @__PURE__ */ new Set();
|
|
10
|
+
try {
|
|
11
|
+
const pkg = JSON.parse(readFileSync(resolve(cwd, "package.json"), "utf-8"));
|
|
12
|
+
for (const field of [
|
|
13
|
+
pkg.dependencies,
|
|
14
|
+
pkg.devDependencies,
|
|
15
|
+
pkg.peerDependencies
|
|
16
|
+
]) for (const name of Object.keys(field ?? {})) names.add(name);
|
|
17
|
+
} catch {}
|
|
18
|
+
return names;
|
|
19
|
+
}
|
|
20
|
+
//#endregion
|
|
21
|
+
//#region src/oxlint.ts
|
|
22
|
+
const baseOxlintConfig = defineConfig({
|
|
9
23
|
categories: {
|
|
10
24
|
correctness: "error",
|
|
11
25
|
suspicious: "warn",
|
|
@@ -474,13 +488,6 @@ const baseOxlintConfig = defineConfig$1({
|
|
|
474
488
|
}
|
|
475
489
|
]
|
|
476
490
|
});
|
|
477
|
-
const baseOxfmtConfig = defineConfig({
|
|
478
|
-
singleQuote: true,
|
|
479
|
-
semi: false,
|
|
480
|
-
arrowParens: "avoid",
|
|
481
|
-
sortImports: true,
|
|
482
|
-
quoteProps: "consistent"
|
|
483
|
-
});
|
|
484
491
|
const basePlugins = [
|
|
485
492
|
"import",
|
|
486
493
|
"unicorn",
|
|
@@ -489,18 +496,14 @@ const basePlugins = [
|
|
|
489
496
|
"promise",
|
|
490
497
|
"oxc"
|
|
491
498
|
];
|
|
492
|
-
const
|
|
499
|
+
const pluginDetectors = {
|
|
493
500
|
typescript: {
|
|
494
501
|
packages: ["typescript"],
|
|
495
502
|
plugins: ["typescript"]
|
|
496
503
|
},
|
|
497
504
|
react: {
|
|
498
505
|
packages: ["react"],
|
|
499
|
-
plugins: [
|
|
500
|
-
"react",
|
|
501
|
-
"jsx-a11y",
|
|
502
|
-
"react-perf"
|
|
503
|
-
]
|
|
506
|
+
plugins: ["react", "jsx-a11y"]
|
|
504
507
|
},
|
|
505
508
|
vue: {
|
|
506
509
|
packages: ["vue"],
|
|
@@ -519,35 +522,19 @@ const pluginToggles = {
|
|
|
519
522
|
plugins: ["jest"]
|
|
520
523
|
}
|
|
521
524
|
};
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
const names = /* @__PURE__ */ new Set();
|
|
525
|
-
try {
|
|
526
|
-
const pkg = JSON.parse(readFileSync(resolve(cwd, "package.json"), "utf-8"));
|
|
527
|
-
for (const field of [
|
|
528
|
-
pkg.dependencies,
|
|
529
|
-
pkg.devDependencies,
|
|
530
|
-
pkg.peerDependencies
|
|
531
|
-
]) for (const name of Object.keys(field ?? {})) names.add(name);
|
|
532
|
-
} catch {}
|
|
533
|
-
return names;
|
|
534
|
-
}
|
|
535
|
-
function resolvePlugins(options, installed) {
|
|
525
|
+
function resolvePlugins(cwd) {
|
|
526
|
+
const installed = getInstalledPackages(cwd);
|
|
536
527
|
const plugins = [...basePlugins];
|
|
537
|
-
for (const
|
|
538
|
-
const toggle = pluginToggles[name];
|
|
539
|
-
if (options[name] ?? toggle.packages.some((pkg) => installed.has(pkg))) plugins.push(...toggle.plugins);
|
|
540
|
-
}
|
|
528
|
+
for (const { packages, plugins: enabled } of Object.values(pluginDetectors)) if (packages.some((pkg) => installed.has(pkg))) plugins.push(...enabled);
|
|
541
529
|
return [...new Set(plugins)];
|
|
542
530
|
}
|
|
543
531
|
/**
|
|
544
532
|
* Build an oxlint config.
|
|
545
533
|
*
|
|
546
|
-
*
|
|
547
|
-
* `
|
|
548
|
-
*
|
|
549
|
-
*
|
|
550
|
-
* manually:
|
|
534
|
+
* Plugins are auto-enabled by detecting their package (`typescript`, `react`,
|
|
535
|
+
* `vue`, `next`, `vitest`, `jest`) in the nearest `package.json`. To enable a
|
|
536
|
+
* plugin whose dependency lives elsewhere — e.g. a nested workspace like
|
|
537
|
+
* `apps/web/package.json` — add it through `overrides.plugins`.
|
|
551
538
|
*
|
|
552
539
|
* @example
|
|
553
540
|
* ```ts
|
|
@@ -556,33 +543,61 @@ function resolvePlugins(options, installed) {
|
|
|
556
543
|
* ```
|
|
557
544
|
* @example
|
|
558
545
|
* ```ts
|
|
559
|
-
* //
|
|
560
|
-
* export default oxlintConfig({ vue:
|
|
546
|
+
* // enable a plugin by hand, tweak a rule
|
|
547
|
+
* export default oxlintConfig({ plugins: ['vue'], rules: { 'no-console': 'off' } })
|
|
561
548
|
* ```
|
|
562
549
|
* @example
|
|
563
550
|
* ```ts
|
|
564
|
-
* // Tailwind
|
|
565
|
-
* export default oxlintConfig({
|
|
566
|
-
* tailwind: true,
|
|
567
|
-
* override: {
|
|
568
|
-
* settings: { 'better-tailwindcss': { entryPoint: 'src/styles/globals.css' } },
|
|
569
|
-
* },
|
|
570
|
-
* })
|
|
551
|
+
* // add Tailwind linting
|
|
552
|
+
* export default oxlintConfig({ ...tailwind({ entryPoint: 'app/globals.css' }) })
|
|
571
553
|
* ```
|
|
572
554
|
*/
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
const { override = {} } = options;
|
|
576
|
-
const installed = getInstalledPackages(options.cwd ?? process.cwd());
|
|
577
|
-
let tailwind = options.tailwind ?? installed.has("tailwindcss");
|
|
578
|
-
if (tailwind && !installed.has(TAILWIND_PLUGIN)) {
|
|
579
|
-
console.warn(`[@letstri/oxc-config] Tailwind linting needs "${TAILWIND_PLUGIN}". Install it: pnpm add -D ${TAILWIND_PLUGIN}`);
|
|
580
|
-
tailwind = false;
|
|
581
|
-
}
|
|
582
|
-
return defu(override, { plugins: resolvePlugins(options, installed) }, tailwind ? tailwindConfig : {}, baseOxlintConfig);
|
|
555
|
+
function oxlintConfig(overrides = {}) {
|
|
556
|
+
return defu(overrides, { plugins: resolvePlugins(process.cwd()) }, baseOxlintConfig);
|
|
583
557
|
}
|
|
584
|
-
|
|
585
|
-
|
|
558
|
+
//#endregion
|
|
559
|
+
//#region src/oxfmt.ts
|
|
560
|
+
const baseOxfmtConfig = defineConfig$1({
|
|
561
|
+
singleQuote: true,
|
|
562
|
+
semi: false,
|
|
563
|
+
arrowParens: "avoid",
|
|
564
|
+
sortImports: true,
|
|
565
|
+
quoteProps: "consistent"
|
|
566
|
+
});
|
|
567
|
+
function oxfmtConfig(overrides = {}) {
|
|
568
|
+
return defu(overrides, baseOxfmtConfig);
|
|
569
|
+
}
|
|
570
|
+
//#endregion
|
|
571
|
+
//#region src/tailwind.ts
|
|
572
|
+
const TAILWIND_PLUGIN = "eslint-plugin-better-tailwindcss";
|
|
573
|
+
/**
|
|
574
|
+
* Tailwind linting via [`eslint-plugin-better-tailwindcss`](https://github.com/schoero/eslint-plugin-better-tailwindcss).
|
|
575
|
+
* Spread the result into `oxlintConfig`:
|
|
576
|
+
*
|
|
577
|
+
* ```ts
|
|
578
|
+
* export default oxlintConfig({ ...tailwind({ entryPoint: 'app/globals.css' }) })
|
|
579
|
+
* ```
|
|
580
|
+
*
|
|
581
|
+
* The plugin is an optional peer dependency — install it yourself
|
|
582
|
+
* (`pnpm add -D eslint-plugin-better-tailwindcss`). If it is missing, an error
|
|
583
|
+
* is thrown.
|
|
584
|
+
*/
|
|
585
|
+
function tailwind({ entryPoint, cwd = process.cwd() }) {
|
|
586
|
+
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
|
+
return defineConfig({
|
|
588
|
+
jsPlugins: [TAILWIND_PLUGIN],
|
|
589
|
+
settings: { "better-tailwindcss": { entryPoint } },
|
|
590
|
+
rules: {
|
|
591
|
+
"better-tailwindcss/enforce-consistent-class-order": "error",
|
|
592
|
+
"better-tailwindcss/enforce-consistent-line-wrapping": "off",
|
|
593
|
+
"better-tailwindcss/no-unnecessary-whitespace": "off",
|
|
594
|
+
"better-tailwindcss/enforce-canonical-classes": "error",
|
|
595
|
+
"better-tailwindcss/no-conflicting-classes": "error",
|
|
596
|
+
"better-tailwindcss/no-deprecated-classes": "error",
|
|
597
|
+
"better-tailwindcss/no-duplicate-classes": "error",
|
|
598
|
+
"better-tailwindcss/no-unknown-classes": "error"
|
|
599
|
+
}
|
|
600
|
+
});
|
|
586
601
|
}
|
|
587
602
|
//#endregion
|
|
588
|
-
export { oxfmtConfig, oxlintConfig };
|
|
603
|
+
export { oxfmtConfig, oxlintConfig, tailwind };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@letstri/oxc-config",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Opinionated Oxlint and Oxfmt configs",
|
|
5
5
|
"homepage": "https://github.com/letstri/oxc-config#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -27,19 +27,6 @@
|
|
|
27
27
|
"publishConfig": {
|
|
28
28
|
"access": "public"
|
|
29
29
|
},
|
|
30
|
-
"scripts": {
|
|
31
|
-
"build": "tsdown",
|
|
32
|
-
"dev": "tsdown --watch",
|
|
33
|
-
"check-types": "tsc --noEmit",
|
|
34
|
-
"lint": "oxlint -c oxlint.config.ts",
|
|
35
|
-
"lint:fix": "oxlint -c oxlint.config.ts --fix",
|
|
36
|
-
"format": "oxfmt -c oxfmt.config.ts",
|
|
37
|
-
"format:check": "oxfmt -c oxfmt.config.ts --check",
|
|
38
|
-
"check": "run-p lint check-types format:check",
|
|
39
|
-
"update": "taze -r -I major",
|
|
40
|
-
"prepare": "husky",
|
|
41
|
-
"prepublishOnly": "pnpm run build"
|
|
42
|
-
},
|
|
43
30
|
"dependencies": {
|
|
44
31
|
"defu": "^6.1.7"
|
|
45
32
|
},
|
|
@@ -66,5 +53,15 @@
|
|
|
66
53
|
"engines": {
|
|
67
54
|
"node": ">=22"
|
|
68
55
|
},
|
|
69
|
-
"
|
|
70
|
-
|
|
56
|
+
"scripts": {
|
|
57
|
+
"build": "tsdown",
|
|
58
|
+
"dev": "tsdown --watch",
|
|
59
|
+
"check-types": "tsc --noEmit",
|
|
60
|
+
"lint": "oxlint -c oxlint.config.ts",
|
|
61
|
+
"lint:fix": "oxlint -c oxlint.config.ts --fix",
|
|
62
|
+
"format": "oxfmt -c oxfmt.config.ts",
|
|
63
|
+
"format:check": "oxfmt -c oxfmt.config.ts --check",
|
|
64
|
+
"check": "run-p lint check-types format:check",
|
|
65
|
+
"update": "taze -r -I major"
|
|
66
|
+
}
|
|
67
|
+
}
|