@bilazo/oxc-config 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/README.md +451 -2
- package/dist/format.d.mts +13 -0
- package/dist/format.d.mts.map +1 -0
- package/dist/format.mjs +98 -0
- package/dist/format.mjs.map +1 -0
- package/dist/lint.d.mts +90 -0
- package/dist/lint.d.mts.map +1 -0
- package/dist/lint.mjs +608 -0
- package/dist/lint.mjs.map +1 -0
- package/package.json +77 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 bilazo
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,452 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @bilazo/oxc-config
|
|
2
2
|
|
|
3
|
-
This
|
|
3
|
+
> **Note:** This is a community preset collection for the [Oxc](https://oxc.rs) toolchain. Not affiliated with the official Oxc project.
|
|
4
|
+
|
|
5
|
+
Shared [Oxlint](https://oxc.rs/) + [Oxfmt](https://oxc.rs/docs/guide/usage/formatter) presets for my projects. One install, lint and format ready.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pnpm add -D @bilazo/oxc-config
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
> [!TIP]
|
|
14
|
+
> Works with pnpm strict mode out of the box — jsPlugin paths are resolved internally via `require.resolve()`, no hoisting hacks needed.
|
|
15
|
+
|
|
16
|
+
## Lint (Oxlint)
|
|
17
|
+
|
|
18
|
+
Create `oxlint.config.ts` in your project root:
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
import { base, unicorn, depend, reactVite, tailwind } from '@bilazo/oxc-config/lint'
|
|
22
|
+
import { defineConfig } from 'oxlint'
|
|
23
|
+
|
|
24
|
+
export default defineConfig({
|
|
25
|
+
extends: [base(), unicorn(), depend(), reactVite(), tailwind()],
|
|
26
|
+
})
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Every preset is a function. Call without arguments for defaults, or pass overrides:
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
export default defineConfig({
|
|
33
|
+
extends: [
|
|
34
|
+
base({ rules: { 'no-console': 'off' } }),
|
|
35
|
+
unicorn({ rules: { 'unicorn/no-array-for-each': 'off' } }),
|
|
36
|
+
vitest({ files: ['**/*.e2e-spec.ts', '**/*.spec.ts'] }),
|
|
37
|
+
],
|
|
38
|
+
})
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
> [!IMPORTANT]
|
|
42
|
+
> Most presets use deep merge via `defu` — user values take priority. File scope options **replace** their defaults (e.g. `vitest({ files: [...] })` replaces the default test globs).
|
|
43
|
+
|
|
44
|
+
### Available presets
|
|
45
|
+
|
|
46
|
+
#### Core
|
|
47
|
+
|
|
48
|
+
| Preset | Description |
|
|
49
|
+
| ------------- | ------------------------------------------------------------------- |
|
|
50
|
+
| `base()` | TypeScript, Import, categories, env, ignores. Always include first. |
|
|
51
|
+
| `typeAware()` | 59 type-aware rules via tsgolint (requires TS-compatible tsconfig) |
|
|
52
|
+
| `unicorn()` | 100+ code quality rules |
|
|
53
|
+
| `depend()` | Flag packages replaceable with native APIs or micro-utilities |
|
|
54
|
+
|
|
55
|
+
#### Runtime
|
|
56
|
+
|
|
57
|
+
| Preset | Description |
|
|
58
|
+
| ----------- | --------------------------------- |
|
|
59
|
+
| `node()` | Node.js specific rules |
|
|
60
|
+
| `promise()` | Promise best practices (16 rules) |
|
|
61
|
+
|
|
62
|
+
#### Frontend
|
|
63
|
+
|
|
64
|
+
| Preset | Description |
|
|
65
|
+
| ------------------ | --------------------------------------------------------------- |
|
|
66
|
+
| `react()` | React + React Hooks — core rules for any React setup |
|
|
67
|
+
| `reactVite()` | React + React Hooks + React Refresh (for Vite) |
|
|
68
|
+
| `nextjs()` | Next.js rules + Core Web Vitals |
|
|
69
|
+
| `tanstackRouter()` | TanStack Router — routing rules + route folder naming convention |
|
|
70
|
+
| `tanstackStart()` | TanStack Start — server/client boundaries, SSR safety |
|
|
71
|
+
| `tailwind()` | Tailwind class consistency (better-tailwindcss plugin) |
|
|
72
|
+
|
|
73
|
+
#### Backend / ORM
|
|
74
|
+
|
|
75
|
+
| Preset | Description |
|
|
76
|
+
| ----------- | ---------------------------------------------------------------------- |
|
|
77
|
+
| `nestjs()` | NestJS DI validation, Swagger consistency, decorator checks (14 rules) |
|
|
78
|
+
| `drizzle()` | Drizzle ORM — enforce where clause on delete/update |
|
|
79
|
+
|
|
80
|
+
#### Quality
|
|
81
|
+
|
|
82
|
+
| Preset | Description |
|
|
83
|
+
| --------- | ------------------------ |
|
|
84
|
+
| `a11y()` | JSX accessibility (WCAG) |
|
|
85
|
+
| `jsdoc()` | JSDoc validation |
|
|
86
|
+
|
|
87
|
+
#### Testing
|
|
88
|
+
|
|
89
|
+
| Preset | Description |
|
|
90
|
+
| ---------- | ---------------------------------------- |
|
|
91
|
+
| `vitest()` | Vitest best practices, environment-aware |
|
|
92
|
+
|
|
93
|
+
### Which React preset should I use?
|
|
94
|
+
|
|
95
|
+
| Project type | Presets to use |
|
|
96
|
+
| ------------------------- | ------------------------------------------------- |
|
|
97
|
+
| Next.js | `nextjs()` + `react()` |
|
|
98
|
+
| Vite + React | `reactVite()` |
|
|
99
|
+
| TanStack Router (SPA) | `reactVite()` + `tanstackRouter()` |
|
|
100
|
+
| TanStack Start | `reactVite()` + `tanstackRouter()` + `tanstackStart()` |
|
|
101
|
+
| Plain React (custom build)| `react()` |
|
|
102
|
+
|
|
103
|
+
> `reactVite()` adds `eslint-plugin-react-refresh` to warn about incorrect fast-refresh patterns — use it for any Vite-based setup.
|
|
104
|
+
|
|
105
|
+
### React rules
|
|
106
|
+
|
|
107
|
+
The `react()` and `reactVite()` presets enable **~27 rules** covering:
|
|
108
|
+
|
|
109
|
+
- **Hooks (critical):** `rules-of-hooks`, `exhaustive-deps`
|
|
110
|
+
- **JSX correctness:** `jsx-key`, `jsx-no-duplicate-props`, `jsx-no-undef`, `jsx-no-target-blank`, `jsx-no-script-url`, `jsx-no-comment-textnodes`
|
|
111
|
+
- **JSX style:** `jsx-boolean-value`, `jsx-curly-brace-presence`, `jsx-fragments`, `jsx-pascal-case`, `self-closing-comp`, `hook-use-state`
|
|
112
|
+
- **Runtime safety:** `no-children-prop`, `no-danger-with-children`, `no-deprecated`, `no-direct-mutation-state`, `no-find-dom-node`, `no-is-mounted`, `no-render-return-value`, `no-string-refs`, `no-unknown-property`, `no-unsafe`, `require-render-return`, `void-dom-elements-no-children`
|
|
113
|
+
|
|
114
|
+
Modern React 17+ is assumed — `react/react-in-jsx-scope` and `react/jsx-uses-react` are off.
|
|
115
|
+
|
|
116
|
+
### TanStack Router
|
|
117
|
+
|
|
118
|
+
The `tanstackRouter()` preset loads [`@tanstack/eslint-plugin-router`](https://www.npmjs.com/package/@tanstack/eslint-plugin-router) and enforces file naming for the `routes/` folder.
|
|
119
|
+
|
|
120
|
+
```ts
|
|
121
|
+
import { base, reactVite, tanstackRouter, tailwind } from '@bilazo/oxc-config/lint'
|
|
122
|
+
import { defineConfig } from 'oxlint'
|
|
123
|
+
|
|
124
|
+
export default defineConfig({
|
|
125
|
+
extends: [base(), reactVite(), tanstackRouter(), tailwind()],
|
|
126
|
+
})
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
**Rules provided:**
|
|
130
|
+
|
|
131
|
+
- `tanstack-router/route-param-names` — validates `$param` names between route path and params
|
|
132
|
+
- `tanstack-router/create-route-property-order` — enforces property order in `createRoute()`
|
|
133
|
+
|
|
134
|
+
**File naming convention:**
|
|
135
|
+
|
|
136
|
+
All files inside a `routes/` folder must be **kebab-case**:
|
|
137
|
+
|
|
138
|
+
| Filename | Valid? | Notes |
|
|
139
|
+
| --------------------------- | ------ | -------------------------------------- |
|
|
140
|
+
| `posts.tsx` | ✅ | |
|
|
141
|
+
| `posts-index.tsx` | ✅ | |
|
|
142
|
+
| `about-page.tsx` | ✅ | |
|
|
143
|
+
| `posts.$postId.tsx` | ✅ | exception: `$` dynamic params |
|
|
144
|
+
| `_auth.tsx` | ✅ | exception: `_` pathless routes |
|
|
145
|
+
| `__root.tsx` | ✅ | exception: `_` prefix |
|
|
146
|
+
| `posts.index.tsx` | ✅ | exception: multiple dots (file nesting)|
|
|
147
|
+
| `Posts.tsx` | ❌ | must be `posts.tsx` |
|
|
148
|
+
| `postsIndex.tsx` | ❌ | must be `posts-index.tsx` |
|
|
149
|
+
| `posts_index.tsx` | ❌ | must be `posts-index.tsx` |
|
|
150
|
+
|
|
151
|
+
> [!NOTE]
|
|
152
|
+
> Folder naming inside `routes/` is **not** covered by Oxlint (linters run file-by-file). To enforce kebab-case for folders, use a separate script or CI step.
|
|
153
|
+
|
|
154
|
+
### TanStack Start
|
|
155
|
+
|
|
156
|
+
The `tanstackStart()` preset adds rules for **server/client boundaries**, **server function safety**, and **SSR conventions**.
|
|
157
|
+
|
|
158
|
+
> [!IMPORTANT]
|
|
159
|
+
> This preset does **not** include `reactVite()` or `tanstackRouter()`. Add them in the correct order:
|
|
160
|
+
>
|
|
161
|
+
> ```ts
|
|
162
|
+
> extends: [base(), reactVite(), tanstackRouter(), tanstackStart(), tailwind(), vitest()]
|
|
163
|
+
> ```
|
|
164
|
+
|
|
165
|
+
**Rules added:**
|
|
166
|
+
|
|
167
|
+
- `no-async-promise-executor`, `consistent-return`, `no-empty-function`
|
|
168
|
+
- `import/no-nodejs-modules` — prevents Node.js APIs from leaking into client bundles
|
|
169
|
+
- `no-restricted-globals` for `window`/`document`/`localStorage`/`sessionStorage` in server files
|
|
170
|
+
|
|
171
|
+
**File scope conventions:**
|
|
172
|
+
|
|
173
|
+
| File pattern | Behavior |
|
|
174
|
+
| --------------------------------------------------------------- | ----------------------------------------------------- |
|
|
175
|
+
| `**/*.server.{ts,tsx}`, `**/server/**`, `**/server-fns/**` | Node.js APIs allowed, browser globals forbidden |
|
|
176
|
+
| `**/*.client.{ts,tsx}`, `**/components/**` | Node.js APIs forbidden |
|
|
177
|
+
| `**/routes/**` | Warning on direct `fetch()` — prefer loaders |
|
|
178
|
+
|
|
179
|
+
**Example:**
|
|
180
|
+
|
|
181
|
+
```ts
|
|
182
|
+
import {
|
|
183
|
+
base,
|
|
184
|
+
unicorn,
|
|
185
|
+
depend,
|
|
186
|
+
reactVite,
|
|
187
|
+
tanstackRouter,
|
|
188
|
+
tanstackStart,
|
|
189
|
+
tailwind,
|
|
190
|
+
vitest,
|
|
191
|
+
} from '@bilazo/oxc-config/lint'
|
|
192
|
+
import { defineConfig } from 'oxlint'
|
|
193
|
+
|
|
194
|
+
export default defineConfig({
|
|
195
|
+
extends: [
|
|
196
|
+
base(),
|
|
197
|
+
unicorn(),
|
|
198
|
+
depend(),
|
|
199
|
+
reactVite(),
|
|
200
|
+
tanstackRouter(),
|
|
201
|
+
tanstackStart(),
|
|
202
|
+
tailwind({ entryPoint: 'src/styles/globals.css' }),
|
|
203
|
+
vitest(),
|
|
204
|
+
],
|
|
205
|
+
})
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### NestJS
|
|
209
|
+
|
|
210
|
+
> [!WARNING]
|
|
211
|
+
> NestJS must disable `typescript/consistent-type-imports` — NestJS DI uses runtime class references in constructor params, and without type-aware linting this rule incorrectly converts them to `import type`, breaking DI at runtime.
|
|
212
|
+
|
|
213
|
+
```ts
|
|
214
|
+
import { base, node, promise, nestjs, drizzle, vitest } from '@bilazo/oxc-config/lint'
|
|
215
|
+
import { defineConfig } from 'oxlint'
|
|
216
|
+
|
|
217
|
+
export default defineConfig({
|
|
218
|
+
extends: [
|
|
219
|
+
base(),
|
|
220
|
+
node(),
|
|
221
|
+
promise(),
|
|
222
|
+
nestjs(),
|
|
223
|
+
drizzle({
|
|
224
|
+
rules: {
|
|
225
|
+
'drizzle/enforce-delete-with-where': ['error', { drizzleObjectName: 'db' }],
|
|
226
|
+
'drizzle/enforce-update-with-where': ['error', { drizzleObjectName: 'db' }],
|
|
227
|
+
},
|
|
228
|
+
}),
|
|
229
|
+
vitest({ files: ['**/*.spec.ts', '**/*.e2e-spec.ts'] }),
|
|
230
|
+
],
|
|
231
|
+
rules: {
|
|
232
|
+
// NestJS exception filter .catch() is not Promise.catch()
|
|
233
|
+
'promise/valid-params': 'off',
|
|
234
|
+
},
|
|
235
|
+
overrides: [
|
|
236
|
+
{
|
|
237
|
+
files: ['**/*.{ts,mts,cts,tsx}'],
|
|
238
|
+
rules: {
|
|
239
|
+
'typescript/consistent-type-imports': 'off',
|
|
240
|
+
'typescript/no-extraneous-class': ['error', { allowWithDecorator: true }],
|
|
241
|
+
},
|
|
242
|
+
},
|
|
243
|
+
],
|
|
244
|
+
})
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
### Type-aware linting
|
|
248
|
+
|
|
249
|
+
The `typeAware()` preset enables two options on oxlint:
|
|
250
|
+
|
|
251
|
+
- **`typeAware`** — turns on ~59 lint rules that need type information, implemented via [`oxlint-tsgolint`](https://www.npmjs.com/package/oxlint-tsgolint) (e.g. `no-floating-promises`, `no-misused-promises`, `consistent-type-imports`)
|
|
252
|
+
- **`typeCheck`** — pipes the TypeScript compiler's own diagnostics (`TS2322`, `TS6133`, `TS2307`, ...) through oxlint, so `oxlint` reports type errors alongside lint violations
|
|
253
|
+
|
|
254
|
+
```ts
|
|
255
|
+
import { base, typeAware, unicorn } from '@bilazo/oxc-config/lint'
|
|
256
|
+
import { defineConfig } from 'oxlint'
|
|
257
|
+
|
|
258
|
+
export default defineConfig({
|
|
259
|
+
extends: [base(), typeAware(), unicorn()],
|
|
260
|
+
})
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
> [!IMPORTANT]
|
|
264
|
+
> `typeAware` and `typeCheck` are **root-config-only** options. Oxlint will error if either is set in a nested (per-package) config file. Always place `typeAware()` in the root config only.
|
|
265
|
+
|
|
266
|
+
Each package's own `tsconfig.json` is auto-detected by oxlint — no extra configuration needed.
|
|
267
|
+
|
|
268
|
+
#### Do I still need a separate `tsc --noEmit` step?
|
|
269
|
+
|
|
270
|
+
**Yes, keep it.** With `typeCheck` enabled, `oxlint` already surfaces tsc diagnostics for the files it lints, so during local development you'll usually catch type errors from `lint` alone. But a dedicated `typecheck` script is still worth keeping because:
|
|
271
|
+
|
|
272
|
+
- **Different file scope.** `tsc --noEmit` honors the tsconfig's `include`/`exclude`. `oxlint` walks the filesystem by its own rules and honors `ignorePatterns`. The two sets overlap but are not identical.
|
|
273
|
+
- **Project-level diagnostics.** tsc catches errors that aren't attached to a single source file: `tsconfig.json` misconfiguration (`TS5xxx`), broken project `references`, `paths` alias typos.
|
|
274
|
+
- **Clearer CI failures.** Running `typecheck` and `lint` as separate steps makes it obvious whether a red build is a type error or a lint rule violation.
|
|
275
|
+
|
|
276
|
+
### Monorepo (nested configs)
|
|
277
|
+
|
|
278
|
+
Oxlint supports [nested configuration](https://oxc.rs/docs/guide/usage/linter/nested-config.html) for monorepos. Each package can have its own `oxlint.config.ts` that extends the root config and adds package-specific presets.
|
|
279
|
+
|
|
280
|
+
#### Root config
|
|
281
|
+
|
|
282
|
+
```ts
|
|
283
|
+
// oxlint.config.ts (root)
|
|
284
|
+
import { base, typeAware, unicorn, depend } from '@bilazo/oxc-config/lint'
|
|
285
|
+
import { defineConfig } from 'oxlint'
|
|
286
|
+
|
|
287
|
+
export default defineConfig({
|
|
288
|
+
extends: [base(), typeAware(), unicorn(), depend()],
|
|
289
|
+
})
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
#### Package configs
|
|
293
|
+
|
|
294
|
+
```ts
|
|
295
|
+
// packages/web/oxlint.config.ts
|
|
296
|
+
import rootConfig from '../../oxlint.config.ts'
|
|
297
|
+
import { reactVite, tanstackRouter, tanstackStart, vitest, tailwind } from '@bilazo/oxc-config/lint'
|
|
298
|
+
import { defineConfig } from 'oxlint'
|
|
299
|
+
|
|
300
|
+
export default defineConfig({
|
|
301
|
+
extends: [rootConfig, reactVite(), tanstackRouter(), tanstackStart(), vitest(), tailwind()],
|
|
302
|
+
})
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
```ts
|
|
306
|
+
// packages/api/oxlint.config.ts
|
|
307
|
+
import rootConfig from '../../oxlint.config.ts'
|
|
308
|
+
import { node, nestjs, drizzle, vitest } from '@bilazo/oxc-config/lint'
|
|
309
|
+
import { defineConfig } from 'oxlint'
|
|
310
|
+
|
|
311
|
+
export default defineConfig({
|
|
312
|
+
extends: [rootConfig, node(), nestjs(), drizzle(), vitest()],
|
|
313
|
+
})
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
> [!TIP]
|
|
317
|
+
> Packages without their own `oxlint.config.ts` automatically use the root config.
|
|
318
|
+
|
|
319
|
+
> [!WARNING]
|
|
320
|
+
> Passing `-c` or `--config` explicitly on the CLI **disables** nested config lookup. Let oxlint auto-detect configs by running without `-c`.
|
|
321
|
+
|
|
322
|
+
## Format (Oxfmt)
|
|
323
|
+
|
|
324
|
+
Create `oxfmt.config.ts`:
|
|
325
|
+
|
|
326
|
+
```ts
|
|
327
|
+
import { format } from '@bilazo/oxc-config/format'
|
|
328
|
+
import { defineConfig } from 'oxfmt'
|
|
329
|
+
|
|
330
|
+
export default defineConfig({ ...format() })
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
### Defaults
|
|
334
|
+
|
|
335
|
+
| Option | Value |
|
|
336
|
+
| -------------------- | --------------------- |
|
|
337
|
+
| `semi` | `false` |
|
|
338
|
+
| `singleQuote` | `true` |
|
|
339
|
+
| `trailingComma` | `all` |
|
|
340
|
+
| `printWidth` | `100` |
|
|
341
|
+
| `tabWidth` | `2` |
|
|
342
|
+
| `endOfLine` | `lf` |
|
|
343
|
+
| Import sorting | Grouped with newlines |
|
|
344
|
+
| Package.json sorting | Enabled |
|
|
345
|
+
| Ignore patterns | Build outputs, lockfiles, generated files |
|
|
346
|
+
|
|
347
|
+
### Override
|
|
348
|
+
|
|
349
|
+
```ts
|
|
350
|
+
export default defineConfig({
|
|
351
|
+
...format({ printWidth: 120, semi: true }),
|
|
352
|
+
})
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
### Tailwind class sorting
|
|
356
|
+
|
|
357
|
+
```ts
|
|
358
|
+
import { format, tailwindFormat } from '@bilazo/oxc-config/format'
|
|
359
|
+
|
|
360
|
+
export default defineConfig({
|
|
361
|
+
...format(),
|
|
362
|
+
...tailwindFormat({ stylesheet: 'src/styles/globals.css' }),
|
|
363
|
+
})
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
### Editor setup (recommended)
|
|
367
|
+
|
|
368
|
+
To keep line endings consistent and avoid the "final newline flip-flop" problem, add an `.editorconfig` at the root of every project:
|
|
369
|
+
|
|
370
|
+
```ini
|
|
371
|
+
root = true
|
|
372
|
+
|
|
373
|
+
[*]
|
|
374
|
+
charset = utf-8
|
|
375
|
+
end_of_line = lf
|
|
376
|
+
insert_final_newline = true
|
|
377
|
+
trim_trailing_whitespace = true
|
|
378
|
+
indent_style = space
|
|
379
|
+
indent_size = 2
|
|
380
|
+
max_line_length = 100
|
|
381
|
+
|
|
382
|
+
[*.md]
|
|
383
|
+
trim_trailing_whitespace = false
|
|
384
|
+
|
|
385
|
+
[*.{yml,yaml}]
|
|
386
|
+
indent_size = 2
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
Most modern editors support EditorConfig natively or via a plugin. This ensures LF endings and a single trailing newline across every file.
|
|
390
|
+
|
|
391
|
+
## Scripts
|
|
392
|
+
|
|
393
|
+
```json
|
|
394
|
+
{
|
|
395
|
+
"scripts": {
|
|
396
|
+
"lint": "oxlint .",
|
|
397
|
+
"lint:fix": "oxlint . --fix",
|
|
398
|
+
"format": "oxfmt .",
|
|
399
|
+
"format:check": "oxfmt --check .",
|
|
400
|
+
"typecheck": "tsc --noEmit"
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
## Full-stack example (TanStack Start + NestJS)
|
|
406
|
+
|
|
407
|
+
```ts
|
|
408
|
+
// apps/web/oxlint.config.ts
|
|
409
|
+
import rootConfig from '../../oxlint.config.ts'
|
|
410
|
+
import { reactVite, tanstackRouter, tanstackStart, tailwind, vitest } from '@bilazo/oxc-config/lint'
|
|
411
|
+
import { defineConfig } from 'oxlint'
|
|
412
|
+
|
|
413
|
+
export default defineConfig({
|
|
414
|
+
extends: [
|
|
415
|
+
rootConfig,
|
|
416
|
+
reactVite(),
|
|
417
|
+
tanstackRouter(),
|
|
418
|
+
tanstackStart(),
|
|
419
|
+
tailwind(),
|
|
420
|
+
vitest(),
|
|
421
|
+
],
|
|
422
|
+
})
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
```ts
|
|
426
|
+
// apps/api/oxlint.config.ts
|
|
427
|
+
import rootConfig from '../../oxlint.config.ts'
|
|
428
|
+
import { node, promise, nestjs, drizzle, vitest } from '@bilazo/oxc-config/lint'
|
|
429
|
+
import { defineConfig } from 'oxlint'
|
|
430
|
+
|
|
431
|
+
export default defineConfig({
|
|
432
|
+
extends: [rootConfig, node(), promise(), nestjs(), drizzle(), vitest()],
|
|
433
|
+
overrides: [
|
|
434
|
+
{
|
|
435
|
+
files: ['**/*.{ts,mts,cts,tsx}'],
|
|
436
|
+
rules: {
|
|
437
|
+
'typescript/consistent-type-imports': 'off',
|
|
438
|
+
'typescript/no-extraneous-class': ['error', { allowWithDecorator: true }],
|
|
439
|
+
},
|
|
440
|
+
},
|
|
441
|
+
],
|
|
442
|
+
})
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
## License
|
|
446
|
+
|
|
447
|
+
MIT
|
|
448
|
+
|
|
449
|
+
## Sources
|
|
450
|
+
|
|
451
|
+
1. [Oxlint: Writing JS Plugins](https://oxc.rs/docs/guide/usage/linter/writing-js-plugins.html)
|
|
452
|
+
2. [infra-code source](https://github.com/oNo500/infra-code/tree/master/packages/code-quality)
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { OxfmtConfig } from "oxfmt";
|
|
2
|
+
//#region src/format.d.ts
|
|
3
|
+
/** Base format preset. Pass overrides to customize. */
|
|
4
|
+
export declare function format(overrides?: Record<string, unknown>): OxfmtConfig;
|
|
5
|
+
/**
|
|
6
|
+
* Oxfmt Tailwind class-sorting preset.
|
|
7
|
+
* Spread into your format config alongside `format()` to enable.
|
|
8
|
+
*/
|
|
9
|
+
export declare function tailwindFormat(options?: {
|
|
10
|
+
stylesheet?: string;
|
|
11
|
+
}): OxfmtConfig;
|
|
12
|
+
//#endregion
|
|
13
|
+
//# sourceMappingURL=format.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.d.mts","names":[],"sources":["../src/format.ts"],"mappings":";;;wBAqBgB,OAAO,YAAY,0BAA0B;;;;;wBA4E7C,eAAe;EAAW;IAA6B"}
|
package/dist/format.mjs
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { defu } from "defu";
|
|
2
|
+
//#region src/format.ts
|
|
3
|
+
/**
|
|
4
|
+
* Oxfmt format presets.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* // oxfmt.config.ts
|
|
9
|
+
* import { format, tailwindFormat } from '@bilazo/oxc-config/format'
|
|
10
|
+
* import { defineConfig } from 'oxfmt'
|
|
11
|
+
*
|
|
12
|
+
* export default defineConfig({
|
|
13
|
+
* ...format(),
|
|
14
|
+
* ...tailwindFormat({ stylesheet: 'src/styles/globals.css' }),
|
|
15
|
+
* })
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
/** Base format preset. Pass overrides to customize. */
|
|
19
|
+
function format(overrides) {
|
|
20
|
+
return defu(overrides, {
|
|
21
|
+
printWidth: 100,
|
|
22
|
+
tabWidth: 2,
|
|
23
|
+
useTabs: false,
|
|
24
|
+
endOfLine: "lf",
|
|
25
|
+
semi: false,
|
|
26
|
+
singleQuote: true,
|
|
27
|
+
jsxSingleQuote: false,
|
|
28
|
+
quoteProps: "consistent",
|
|
29
|
+
trailingComma: "all",
|
|
30
|
+
bracketSpacing: true,
|
|
31
|
+
bracketSameLine: false,
|
|
32
|
+
arrowParens: "always",
|
|
33
|
+
sortPackageJson: true,
|
|
34
|
+
sortImports: {
|
|
35
|
+
groups: [
|
|
36
|
+
"builtin",
|
|
37
|
+
{ newlinesBetween: true },
|
|
38
|
+
"external",
|
|
39
|
+
{ newlinesBetween: true },
|
|
40
|
+
"internal",
|
|
41
|
+
{ newlinesBetween: true },
|
|
42
|
+
["parent", "sibling"],
|
|
43
|
+
{ newlinesBetween: true },
|
|
44
|
+
"index",
|
|
45
|
+
{ newlinesBetween: true },
|
|
46
|
+
"type"
|
|
47
|
+
],
|
|
48
|
+
internalPattern: [
|
|
49
|
+
"~/",
|
|
50
|
+
"@/",
|
|
51
|
+
"#/"
|
|
52
|
+
]
|
|
53
|
+
},
|
|
54
|
+
ignorePatterns: [
|
|
55
|
+
"dist/**",
|
|
56
|
+
"build/**",
|
|
57
|
+
"out/**",
|
|
58
|
+
".output/**",
|
|
59
|
+
".next/**",
|
|
60
|
+
".turbo/**",
|
|
61
|
+
".cache/**",
|
|
62
|
+
".nitro/**",
|
|
63
|
+
".tanstack/**",
|
|
64
|
+
".vinxi/**",
|
|
65
|
+
".content-collections/**",
|
|
66
|
+
"public/**",
|
|
67
|
+
"coverage/**",
|
|
68
|
+
"**/api",
|
|
69
|
+
"**/build",
|
|
70
|
+
"**/public",
|
|
71
|
+
"routeTree.gen.ts",
|
|
72
|
+
"*.min.js",
|
|
73
|
+
"*.min.css",
|
|
74
|
+
"pnpm-lock.yaml",
|
|
75
|
+
"package-lock.json",
|
|
76
|
+
"yarn.lock"
|
|
77
|
+
]
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Oxfmt Tailwind class-sorting preset.
|
|
82
|
+
* Spread into your format config alongside `format()` to enable.
|
|
83
|
+
*/
|
|
84
|
+
function tailwindFormat(options = {}) {
|
|
85
|
+
return { sortTailwindcss: {
|
|
86
|
+
stylesheet: options.stylesheet ?? "src/styles/globals.css",
|
|
87
|
+
functions: [
|
|
88
|
+
"cn",
|
|
89
|
+
"clsx",
|
|
90
|
+
"cva",
|
|
91
|
+
"tw"
|
|
92
|
+
]
|
|
93
|
+
} };
|
|
94
|
+
}
|
|
95
|
+
//#endregion
|
|
96
|
+
export { format, tailwindFormat };
|
|
97
|
+
|
|
98
|
+
//# sourceMappingURL=format.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.mjs","names":[],"sources":["../src/format.ts"],"sourcesContent":["/**\n * Oxfmt format presets.\n *\n * @example\n * ```ts\n * // oxfmt.config.ts\n * import { format, tailwindFormat } from '@bilazo/oxc-config/format'\n * import { defineConfig } from 'oxfmt'\n *\n * export default defineConfig({\n * ...format(),\n * ...tailwindFormat({ stylesheet: 'src/styles/globals.css' }),\n * })\n * ```\n */\n\nimport { defu } from 'defu'\n\nimport type { OxfmtConfig } from 'oxfmt'\n\n/** Base format preset. Pass overrides to customize. */\nexport function format(overrides?: Record<string, unknown>): OxfmtConfig {\n return defu(overrides, {\n // Layout\n printWidth: 100,\n tabWidth: 2,\n useTabs: false,\n endOfLine: 'lf' as const,\n\n // Quotes & Semicolons\n semi: false,\n singleQuote: true,\n jsxSingleQuote: false,\n quoteProps: 'consistent' as const,\n\n // Trailing & Spacing\n trailingComma: 'all' as const,\n bracketSpacing: true,\n bracketSameLine: false,\n arrowParens: 'always' as const,\n\n // Sorting\n sortPackageJson: true,\n sortImports: {\n groups: [\n 'builtin',\n { newlinesBetween: true },\n 'external',\n { newlinesBetween: true },\n 'internal',\n { newlinesBetween: true },\n ['parent', 'sibling'],\n { newlinesBetween: true },\n 'index',\n { newlinesBetween: true },\n 'type',\n ],\n internalPattern: ['~/', '@/', '#/'],\n },\n\n // Ignore\n ignorePatterns: [\n // Build outputs\n 'dist/**',\n 'build/**',\n 'out/**',\n '.output/**',\n '.next/**',\n '.turbo/**',\n '.cache/**',\n '.nitro/**',\n '.tanstack/**',\n '.vinxi/**',\n '.content-collections/**',\n\n // Generated / vendor\n 'public/**',\n 'coverage/**',\n '**/api',\n '**/build',\n '**/public',\n 'routeTree.gen.ts',\n '*.min.js',\n '*.min.css',\n\n // Lock files\n 'pnpm-lock.yaml',\n 'package-lock.json',\n 'yarn.lock',\n ],\n }) as OxfmtConfig\n}\n\n/**\n * Oxfmt Tailwind class-sorting preset.\n * Spread into your format config alongside `format()` to enable.\n */\nexport function tailwindFormat(options: { stylesheet?: string } = {}): OxfmtConfig {\n return {\n sortTailwindcss: {\n stylesheet: options.stylesheet ?? 'src/styles/globals.css',\n functions: ['cn', 'clsx', 'cva', 'tw'] as string[],\n },\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAqBA,SAAgB,OAAO,WAAkD;CACvE,OAAO,KAAK,WAAW;EAErB,YAAY;EACZ,UAAU;EACV,SAAS;EACT,WAAW;EAGX,MAAM;EACN,aAAa;EACb,gBAAgB;EAChB,YAAY;EAGZ,eAAe;EACf,gBAAgB;EAChB,iBAAiB;EACjB,aAAa;EAGb,iBAAiB;EACjB,aAAa;GACX,QAAQ;IACN;IACA,EAAE,iBAAiB,KAAK;IACxB;IACA,EAAE,iBAAiB,KAAK;IACxB;IACA,EAAE,iBAAiB,KAAK;IACxB,CAAC,UAAU,SAAS;IACpB,EAAE,iBAAiB,KAAK;IACxB;IACA,EAAE,iBAAiB,KAAK;IACxB;GACF;GACA,iBAAiB;IAAC;IAAM;IAAM;GAAI;EACpC;EAGA,gBAAgB;GAEd;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GAGA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GAGA;GACA;GACA;EACF;CACF,CAAC;AACH;;;;;AAMA,SAAgB,eAAe,UAAmC,CAAC,GAAgB;CACjF,OAAO,EACL,iBAAiB;EACf,YAAY,QAAQ,cAAc;EAClC,WAAW;GAAC;GAAM;GAAQ;GAAO;EAAI;CACvC,EACF;AACF"}
|
package/dist/lint.d.mts
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { OxlintConfig, defineConfig } from "oxlint";
|
|
2
|
+
//#region src/utils.d.ts
|
|
3
|
+
/** All JS/TS source files */
|
|
4
|
+
export declare const GLOB_SRC = "**/*.{js,mjs,cjs,jsx,ts,mts,cts,tsx}";
|
|
5
|
+
/** JavaScript files only */
|
|
6
|
+
export declare const GLOB_JS = "**/*.{js,mjs,cjs,jsx}";
|
|
7
|
+
/** TypeScript files only */
|
|
8
|
+
export declare const GLOB_TS = "**/*.{ts,mts,cts,tsx}";
|
|
9
|
+
/** JSX/TSX files (React-related) */
|
|
10
|
+
export declare const GLOB_JSX = "**/*.{jsx,tsx}";
|
|
11
|
+
/** Test files */
|
|
12
|
+
export declare const GLOB_TESTS: string[];
|
|
13
|
+
/** JSON files */
|
|
14
|
+
export declare const GLOB_JSON = "**/*.json";
|
|
15
|
+
/** Markdown files */
|
|
16
|
+
export declare const GLOB_MARKDOWN = "**/*.md";
|
|
17
|
+
//#endregion
|
|
18
|
+
//#region src/lint.d.ts
|
|
19
|
+
/**
|
|
20
|
+
* Base lint preset — TypeScript + Import plugins, categories, env, ignores.
|
|
21
|
+
* Always include first.
|
|
22
|
+
*/
|
|
23
|
+
export declare function base(overrides?: Partial<OxlintConfig>): OxlintConfig;
|
|
24
|
+
/**
|
|
25
|
+
* Type-aware lint preset — enables 59 type-aware rules via tsgolint + type checking.
|
|
26
|
+
* Requires TypeScript 7.0+ and `oxlint-tsgolint` (bundled as dependency).
|
|
27
|
+
*/
|
|
28
|
+
export declare function typeAware(overrides?: Partial<OxlintConfig>): OxlintConfig;
|
|
29
|
+
/** Unicorn lint preset — 100+ code quality rules. */
|
|
30
|
+
export declare function unicorn(overrides?: Partial<OxlintConfig>): OxlintConfig;
|
|
31
|
+
/** Dependency optimization — flags packages replaceable with native APIs. */
|
|
32
|
+
export declare function depend(overrides?: Partial<OxlintConfig>): OxlintConfig;
|
|
33
|
+
/** Node.js lint preset — native node plugin. */
|
|
34
|
+
export declare function node(overrides?: Partial<OxlintConfig>): OxlintConfig;
|
|
35
|
+
/** Promise lint preset — native promise plugin. */
|
|
36
|
+
export declare function promise(overrides?: Partial<OxlintConfig>): OxlintConfig;
|
|
37
|
+
/** React lint preset — core React + Hooks rules. */
|
|
38
|
+
export declare function react(overrides?: Partial<OxlintConfig>): OxlintConfig;
|
|
39
|
+
/** React + react-refresh preset (for Vite, TanStack Start, etc.). */
|
|
40
|
+
export declare function reactVite(overrides?: Partial<OxlintConfig>): OxlintConfig;
|
|
41
|
+
/** Next.js lint preset — enables native nextjs plugin. */
|
|
42
|
+
export declare function nextjs(overrides?: Partial<OxlintConfig>): OxlintConfig;
|
|
43
|
+
/**
|
|
44
|
+
* TanStack Router lint preset.
|
|
45
|
+
*
|
|
46
|
+
* Loads @tanstack/eslint-plugin-router and applies conventions specific
|
|
47
|
+
* to file-based routing setups.
|
|
48
|
+
*
|
|
49
|
+
* Rules provided by the plugin:
|
|
50
|
+
* - `route-param-names` — validates `$param` names match between route path and params
|
|
51
|
+
* - `create-route-property-order` — enforces consistent property order in `createRoute()`
|
|
52
|
+
*/
|
|
53
|
+
export declare function tanstackRouter(overrides?: Partial<OxlintConfig>): OxlintConfig;
|
|
54
|
+
/**
|
|
55
|
+
* TanStack Start lint preset.
|
|
56
|
+
*
|
|
57
|
+
* Adds rules for server functions, client/server boundaries, and Start
|
|
58
|
+
* conventions. This preset assumes `reactVite()` and `tanstackRouter()`
|
|
59
|
+
* are already in the `extends` array.
|
|
60
|
+
*
|
|
61
|
+
*/
|
|
62
|
+
export declare function tanstackStart(overrides?: Partial<OxlintConfig>): OxlintConfig;
|
|
63
|
+
/** Accessibility lint preset — enables native jsx-a11y plugin. */
|
|
64
|
+
export declare function a11y(overrides?: Partial<OxlintConfig>): OxlintConfig;
|
|
65
|
+
/** JSDoc lint preset — enables native jsdoc plugin. */
|
|
66
|
+
export declare function jsdoc(overrides?: Partial<OxlintConfig>): OxlintConfig;
|
|
67
|
+
interface VitestOptions extends Partial<OxlintConfig> {
|
|
68
|
+
/** Test file glob patterns. Replaces the default GLOB_TESTS. */
|
|
69
|
+
files?: string[];
|
|
70
|
+
}
|
|
71
|
+
/** Vitest lint preset — native vitest plugin with test-file scoping. */
|
|
72
|
+
export declare function vitest(options?: VitestOptions): OxlintConfig;
|
|
73
|
+
interface TailwindOptions extends Partial<OxlintConfig> {
|
|
74
|
+
entryPoint?: string;
|
|
75
|
+
rootFontSize?: number;
|
|
76
|
+
/** File glob patterns for tailwind rules. @default GLOB_JSX */
|
|
77
|
+
files?: string[];
|
|
78
|
+
}
|
|
79
|
+
/** Tailwind CSS lint preset — eslint-plugin-better-tailwindcss. */
|
|
80
|
+
export declare function tailwind(options?: TailwindOptions): OxlintConfig;
|
|
81
|
+
/**
|
|
82
|
+
* NestJS lint preset — loads @darraghor/eslint-plugin-nestjs-typed via jsPlugin.
|
|
83
|
+
* Covers DI validation, Swagger consistency, decorator bug prevention (19 AST rules).
|
|
84
|
+
*/
|
|
85
|
+
export declare function nestjs(overrides?: Partial<OxlintConfig>): OxlintConfig;
|
|
86
|
+
/** Drizzle ORM lint preset — eslint-plugin-drizzle. */
|
|
87
|
+
export declare function drizzle(overrides?: Partial<OxlintConfig>): OxlintConfig;
|
|
88
|
+
//#endregion
|
|
89
|
+
export { defineConfig };
|
|
90
|
+
//# sourceMappingURL=lint.d.mts.map
|