@maz-ui/eslint-config 4.9.1 → 5.0.0-beta.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 +83 -102
- package/dist/index.d.mts +87 -12
- package/dist/index.d.ts +87 -12
- package/dist/index.mjs +143 -37
- package/package.json +6 -5
package/README.md
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
# @maz-ui/eslint-config
|
|
2
2
|
|
|
3
|
-
Reusable ESLint configuration for JavaScript/TypeScript projects.
|
|
3
|
+
Reusable ESLint configuration for JavaScript/TypeScript projects, built on top of [`@antfu/eslint-config`](https://github.com/antfu/eslint-config).
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
|
-
- 🚀 **Based on @antfu/eslint-config**
|
|
8
|
-
- 🛡️ **
|
|
9
|
-
- 🎨 **Tailwind CSS** -
|
|
10
|
-
- 🔍 **SonarJS**
|
|
11
|
-
-
|
|
12
|
-
-
|
|
7
|
+
- 🚀 **Based on @antfu/eslint-config** — modern, performant, flat-config first
|
|
8
|
+
- 🛡️ **TypeScript-first** — strict mode, sensible defaults
|
|
9
|
+
- 🎨 **Tailwind CSS v3 + v4** — via [`eslint-plugin-better-tailwindcss`](https://github.com/schoero/eslint-plugin-better-tailwindcss) (compat ESLint 7→10, both Tailwind versions)
|
|
10
|
+
- 🔍 **SonarJS** — code quality / cognitive complexity
|
|
11
|
+
- ♿ **Vue accessibility** — opt-in `eslint-plugin-vuejs-accessibility`
|
|
12
|
+
- 📐 **Formatters** — Prettier-style formatting via `eslint-plugin-format`
|
|
13
|
+
- ⚙️ **Configurable** — pick presets, add per-file rules, custom ignore globs
|
|
13
14
|
|
|
14
15
|
## Installation
|
|
15
16
|
|
|
@@ -26,139 +27,119 @@ import { defineConfig } from '@maz-ui/eslint-config'
|
|
|
26
27
|
export default defineConfig()
|
|
27
28
|
```
|
|
28
29
|
|
|
29
|
-
|
|
30
|
+
Vue / Nuxt are auto-detected from your `package.json`.
|
|
31
|
+
|
|
32
|
+
## Configuration
|
|
30
33
|
|
|
31
34
|
```js
|
|
32
35
|
// eslint.config.js
|
|
33
36
|
import { defineConfig } from '@maz-ui/eslint-config'
|
|
34
37
|
|
|
35
38
|
export default defineConfig({
|
|
36
|
-
//
|
|
37
|
-
env: 'production', // 'development' | 'production'
|
|
39
|
+
env: 'production', // 'development' | 'production' — affects no-console / no-debugger severity
|
|
38
40
|
|
|
39
|
-
//
|
|
41
|
+
// Antfu options (forwarded as-is)
|
|
40
42
|
typescript: true,
|
|
41
|
-
tailwindcss: true,
|
|
42
|
-
sonarjs: true,
|
|
43
43
|
formatters: true,
|
|
44
|
+
unicorn: true,
|
|
45
|
+
|
|
46
|
+
// Maz-UI options
|
|
47
|
+
sonarjs: true,
|
|
48
|
+
vueAccessibility: false,
|
|
49
|
+
tailwindcss: 'recommended', // see "Tailwind support" below
|
|
44
50
|
|
|
45
|
-
//
|
|
51
|
+
// Extra ignore globs (merged with defaults)
|
|
46
52
|
ignores: ['custom-dist/**'],
|
|
47
53
|
|
|
48
54
|
// Custom rules
|
|
49
55
|
rules: {
|
|
50
56
|
'no-console': 'error',
|
|
51
|
-
|
|
52
|
-
|
|
57
|
+
},
|
|
58
|
+
|
|
59
|
+
// 'silent' | 'default' | 'debug' | 'verbose' — see "Logging" below.
|
|
60
|
+
logLevel: 'default',
|
|
53
61
|
})
|
|
54
62
|
```
|
|
55
63
|
|
|
56
|
-
##
|
|
57
|
-
|
|
58
|
-
```typescript
|
|
59
|
-
interface MazESLintOptions {
|
|
60
|
-
typescript?: boolean // TypeScript support (default: true)
|
|
61
|
-
tailwindcss?: boolean // Tailwind CSS rules (default: true)
|
|
62
|
-
sonarjs?: boolean // SonarJS rules (default: true)
|
|
63
|
-
formatters?: boolean // Formatters support (default: true)
|
|
64
|
-
env?: 'development' | 'production' // Environment (default: 'development')
|
|
65
|
-
ignores?: string[] // Files to ignore
|
|
66
|
-
rules?: Record<string, any> // Custom ESLint rules
|
|
67
|
-
}
|
|
68
|
-
```
|
|
64
|
+
## Logging
|
|
69
65
|
|
|
70
|
-
|
|
66
|
+
The preset prints a titled box summarizing what it resolved (typescript, vue, tailwindcss preset, sonarjs, …). Powered by `@maz-ui/node`'s consola-based logger.
|
|
71
67
|
|
|
72
|
-
|
|
68
|
+
| Value | What you see |
|
|
69
|
+
| --------------------------- | -------------------------------------------------- |
|
|
70
|
+
| `'silent'` | Nothing. |
|
|
71
|
+
| `'default'` _(TTY default)_ | Titled box of resolved feature toggles. |
|
|
72
|
+
| `'debug'` | Above + each plugin / preset / overrides addition. |
|
|
73
|
+
| `'verbose'` | Above + final block count and ignore-glob count. |
|
|
73
74
|
|
|
74
|
-
|
|
75
|
-
import { baseRules, sonarjsRules, tailwindcssRules } from '@maz-ui/eslint-config'
|
|
75
|
+
The default is **`'default'` in interactive terminals, `'silent'` otherwise** (CI, pipes, JSON / SARIF formatters). This avoids polluting machine-readable ESLint output. Override by passing `logLevel` explicitly.
|
|
76
76
|
|
|
77
|
-
|
|
78
|
-
{
|
|
79
|
-
rules: {
|
|
80
|
-
...baseRules,
|
|
81
|
-
...sonarjsRules,
|
|
82
|
-
// Your custom rules
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
]
|
|
86
|
-
```
|
|
77
|
+
## Tailwind support
|
|
87
78
|
|
|
88
|
-
|
|
79
|
+
Powered by [`eslint-plugin-better-tailwindcss`](https://github.com/schoero/eslint-plugin-better-tailwindcss) — compatible with ESLint 7→10 and Tailwind v3 + v4.
|
|
89
80
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
81
|
+
| Value | Behavior |
|
|
82
|
+
| ----------------------- | ----------------------------------------------------------------------- |
|
|
83
|
+
| `false` _(default)_ | Disabled. |
|
|
84
|
+
| `true` | Same as `'recommended'` with default settings. |
|
|
85
|
+
| `'recommended'` | Stylistic + correctness rules. |
|
|
86
|
+
| `'stylistic'` | Formatting rules only (class order, line wrapping, …). |
|
|
87
|
+
| `'correctness'` | Validation rules only (`no-unknown-classes`, `no-conflicting-classes`). |
|
|
88
|
+
| `MazTailwindcssOptions` | Pick a preset and pass plugin settings. |
|
|
93
89
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
90
|
+
```js
|
|
91
|
+
defineConfig({
|
|
92
|
+
tailwindcss: {
|
|
93
|
+
preset: 'recommended',
|
|
94
|
+
// Tailwind v4: path to the CSS that does `@import "tailwindcss" prefix(maz)`
|
|
95
|
+
entryPoint: 'src/main.css',
|
|
96
|
+
// Tailwind v3 instead:
|
|
97
|
+
// tailwindConfig: 'tailwind.config.ts',
|
|
98
|
+
detectComponentClasses: true,
|
|
99
|
+
},
|
|
102
100
|
})
|
|
103
101
|
```
|
|
104
102
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
### Base (JavaScript/TypeScript)
|
|
108
|
-
|
|
109
|
-
- Console management by environment
|
|
110
|
-
- Code quality rules
|
|
111
|
-
- Optimized TypeScript support
|
|
112
|
-
|
|
113
|
-
### SonarJS
|
|
114
|
-
|
|
115
|
-
- Limited cognitive complexity
|
|
116
|
-
- Duplicate code detection
|
|
117
|
-
- Security best practices
|
|
103
|
+
> [!IMPORTANT]
|
|
104
|
+
> The plugin's `no-unknown-classes` rule needs to know about your Tailwind setup (prefix, custom utilities, theme tokens). Without `entryPoint` (v4) or `tailwindConfig` (v3), it falls back to the default Tailwind config and will flood with false positives in projects that customize either. **Pass the path explicitly** if your Tailwind setup is non-standard.
|
|
118
105
|
|
|
119
|
-
|
|
106
|
+
## Advanced
|
|
120
107
|
|
|
121
|
-
|
|
122
|
-
- Contradictory class detection
|
|
123
|
-
- Valid Tailwind syntax
|
|
124
|
-
|
|
125
|
-
## Compatibility
|
|
126
|
-
|
|
127
|
-
- **ESLint** ^9.0.0
|
|
128
|
-
- **Node.js** >=18.0.0
|
|
129
|
-
- **TypeScript** ^5.0.0
|
|
130
|
-
|
|
131
|
-
## Usage examples
|
|
132
|
-
|
|
133
|
-
### Simple JavaScript project
|
|
108
|
+
### Compose your own config
|
|
134
109
|
|
|
135
110
|
```js
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
111
|
+
import {
|
|
112
|
+
baseRules,
|
|
113
|
+
sonarjsRules,
|
|
114
|
+
tailwindcssConfigs,
|
|
115
|
+
vueRules,
|
|
116
|
+
} from '@maz-ui/eslint-config'
|
|
117
|
+
|
|
118
|
+
export default [
|
|
119
|
+
{
|
|
120
|
+
rules: {
|
|
121
|
+
...baseRules(true), // production = true
|
|
122
|
+
...sonarjsRules,
|
|
123
|
+
...vueRules,
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
...tailwindcssConfigs('stylistic', { entryPoint: 'src/main.css' }),
|
|
127
|
+
]
|
|
140
128
|
```
|
|
141
129
|
|
|
142
|
-
###
|
|
130
|
+
### Vue project
|
|
143
131
|
|
|
144
132
|
```js
|
|
145
|
-
|
|
146
|
-
|
|
133
|
+
defineConfig({
|
|
134
|
+
vue: true, // auto-detected if `vue` / `nuxt` is in deps
|
|
135
|
+
tailwindcss: 'recommended',
|
|
147
136
|
rules: {
|
|
148
|
-
'
|
|
149
|
-
}
|
|
137
|
+
'vue/custom-event-name-casing': ['error', 'kebab-case'],
|
|
138
|
+
},
|
|
150
139
|
})
|
|
151
140
|
```
|
|
152
141
|
|
|
153
|
-
|
|
142
|
+
## Compatibility
|
|
154
143
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
env: 'production',
|
|
158
|
-
sonarjs: true,
|
|
159
|
-
rules: {
|
|
160
|
-
'no-console': 'error',
|
|
161
|
-
'no-debugger': 'error'
|
|
162
|
-
}
|
|
163
|
-
})
|
|
164
|
-
```
|
|
144
|
+
- **ESLint** `^9.0.0 || ^10.0.0`
|
|
145
|
+
- **Node.js** `>=20.19.0`
|
package/dist/index.d.mts
CHANGED
|
@@ -1,13 +1,73 @@
|
|
|
1
1
|
import { antfu, OptionsConfig, Rules, TypedFlatConfigItem } from '@antfu/eslint-config';
|
|
2
2
|
import { Linter } from 'eslint';
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Mirror of `@maz-ui/node`'s LogLevel — kept inline here to avoid making this
|
|
6
|
+
* preset depend on `@maz-ui/node`, which would create a build cycle (the
|
|
7
|
+
* `eslint.config.ts` of `@maz-ui/node` imports `@maz-ui/eslint-config`, which
|
|
8
|
+
* itself would depend on `@maz-ui/node` for the same logger). Direct usage of
|
|
9
|
+
* `consola` keeps the dependency graph acyclic.
|
|
10
|
+
*/
|
|
11
|
+
type LogLevel = 'silent' | 'error' | 'warning' | 'normal' | 'default' | 'debug' | 'trace' | 'verbose';
|
|
12
|
+
|
|
4
13
|
type MazESLintUserConfig = TypedFlatConfigItem | TypedFlatConfigItem[] | Linter.Config | Linter.Config[];
|
|
14
|
+
type TailwindcssPreset = 'recommended' | 'stylistic' | 'correctness';
|
|
15
|
+
/**
|
|
16
|
+
* Settings forwarded to `eslint-plugin-better-tailwindcss` under
|
|
17
|
+
* `settings['better-tailwindcss']`. See the plugin docs for the canonical
|
|
18
|
+
* meaning of each field.
|
|
19
|
+
*/
|
|
20
|
+
interface MazTailwindcssOptions {
|
|
21
|
+
/**
|
|
22
|
+
* Which preset to load. Each one comes in `*-warn` and `*-error` flavors
|
|
23
|
+
* (defaults match the plugin's defaults: stylistic→warn, correctness→error).
|
|
24
|
+
*
|
|
25
|
+
* @default 'recommended'
|
|
26
|
+
*/
|
|
27
|
+
preset?: TailwindcssPreset;
|
|
28
|
+
/**
|
|
29
|
+
* Tailwind v4: path to the CSS entry file (the one that does
|
|
30
|
+
* `@import "tailwindcss"`, possibly with `prefix(...)`). Required for the
|
|
31
|
+
* plugin to know about your prefix and `@theme` tokens.
|
|
32
|
+
*/
|
|
33
|
+
entryPoint?: string;
|
|
34
|
+
/**
|
|
35
|
+
* Tailwind v3: path to `tailwind.config.{js,ts,cjs,mjs}`. Use `entryPoint`
|
|
36
|
+
* for v4 instead.
|
|
37
|
+
*/
|
|
38
|
+
tailwindConfig?: string;
|
|
39
|
+
/**
|
|
40
|
+
* Tailwind v4: enable detection of custom component classes (`@layer
|
|
41
|
+
* components { … }`) so they are not reported as unknown.
|
|
42
|
+
*
|
|
43
|
+
* @default false
|
|
44
|
+
*/
|
|
45
|
+
detectComponentClasses?: boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Working directory used to resolve `tailwindcss` and the config files
|
|
48
|
+
* above. Useful in monorepos when ESLint runs from the repo root.
|
|
49
|
+
*/
|
|
50
|
+
cwd?: string;
|
|
51
|
+
/**
|
|
52
|
+
* Path to a `tsconfig.json` used to resolve `paths` aliases inside the
|
|
53
|
+
* Tailwind config.
|
|
54
|
+
*/
|
|
55
|
+
tsconfig?: string;
|
|
56
|
+
}
|
|
5
57
|
interface MazESLintOptions extends OptionsConfig {
|
|
6
58
|
/**
|
|
7
|
-
*
|
|
59
|
+
* Tailwind CSS support — wires `eslint-plugin-better-tailwindcss`.
|
|
60
|
+
*
|
|
61
|
+
* - `false` *(default)*: disabled.
|
|
62
|
+
* - `true`: load the `'recommended'` preset with default settings.
|
|
63
|
+
* - `'recommended' | 'stylistic' | 'correctness'`: pick a preset, default
|
|
64
|
+
* settings.
|
|
65
|
+
* - `MazTailwindcssOptions`: pick a preset and pass settings (e.g.
|
|
66
|
+
* `entryPoint` so the plugin learns your v4 prefix).
|
|
67
|
+
*
|
|
8
68
|
* @default false
|
|
9
69
|
*/
|
|
10
|
-
tailwindcss?: boolean;
|
|
70
|
+
tailwindcss?: boolean | TailwindcssPreset | MazTailwindcssOptions;
|
|
11
71
|
/**
|
|
12
72
|
* Enable SonarJS rules for code quality
|
|
13
73
|
* @default true
|
|
@@ -32,6 +92,19 @@ interface MazESLintOptions extends OptionsConfig {
|
|
|
32
92
|
* Additional rules to merge
|
|
33
93
|
*/
|
|
34
94
|
rules?: Partial<Rules>;
|
|
95
|
+
/**
|
|
96
|
+
* Verbosity of the logs emitted while resolving the config. Defaults to
|
|
97
|
+
* `'default'` so the resolved-configuration box is shown when the preset
|
|
98
|
+
* loads. Set to `'silent'` to hide it, or `'debug'` / `'verbose'` to dig
|
|
99
|
+
* deeper.
|
|
100
|
+
*
|
|
101
|
+
* - `'silent'`: nothing is printed.
|
|
102
|
+
* - `'default'` *(default)*: a titled box summarizing the resolved feature
|
|
103
|
+
* toggles.
|
|
104
|
+
* - `'debug'`: also logs each plugin / preset / overrides addition.
|
|
105
|
+
* - `'verbose'`: also logs the final shape (config block count, etc.).
|
|
106
|
+
*/
|
|
107
|
+
logLevel?: LogLevel;
|
|
35
108
|
}
|
|
36
109
|
type MazESLintConfig = ReturnType<typeof antfu>;
|
|
37
110
|
|
|
@@ -68,15 +141,17 @@ declare const sonarjsTestRules: {
|
|
|
68
141
|
};
|
|
69
142
|
|
|
70
143
|
/**
|
|
71
|
-
* Tailwind
|
|
144
|
+
* Files where Tailwind classes commonly live. Exposed for users who want to
|
|
145
|
+
* compose their own config.
|
|
72
146
|
*/
|
|
73
|
-
declare const
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
147
|
+
declare const TAILWINDCSS_DEFAULT_FILES: string[];
|
|
148
|
+
/**
|
|
149
|
+
* Build the flat-config block(s) that wire up
|
|
150
|
+
* `eslint-plugin-better-tailwindcss`. The plugin already ships preset
|
|
151
|
+
* objects with `plugins` + `rules`; we spread them and add `files` plus
|
|
152
|
+
* `settings['better-tailwindcss']` so the user's options reach the plugin.
|
|
153
|
+
*/
|
|
154
|
+
declare function tailwindcssConfigs(preset: TailwindcssPreset, settings: MazTailwindcssOptions): Linter.Config[];
|
|
80
155
|
|
|
81
156
|
declare const vueRules: {
|
|
82
157
|
'vue/custom-event-name-casing': ["error", "kebab-case"];
|
|
@@ -102,5 +177,5 @@ declare const vueRules: {
|
|
|
102
177
|
*/
|
|
103
178
|
declare function defineConfig(options?: MazESLintOptions, ...userConfigs: MazESLintUserConfig[]): MazESLintConfig;
|
|
104
179
|
|
|
105
|
-
export { baseRules, defineConfig, sonarjsRules, sonarjsTestRules,
|
|
106
|
-
export type { MazESLintConfig, MazESLintOptions };
|
|
180
|
+
export { TAILWINDCSS_DEFAULT_FILES, baseRules, defineConfig, sonarjsRules, sonarjsTestRules, tailwindcssConfigs, vueRules };
|
|
181
|
+
export type { MazESLintConfig, MazESLintOptions, MazTailwindcssOptions, TailwindcssPreset };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,13 +1,73 @@
|
|
|
1
1
|
import { antfu, OptionsConfig, Rules, TypedFlatConfigItem } from '@antfu/eslint-config';
|
|
2
2
|
import { Linter } from 'eslint';
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Mirror of `@maz-ui/node`'s LogLevel — kept inline here to avoid making this
|
|
6
|
+
* preset depend on `@maz-ui/node`, which would create a build cycle (the
|
|
7
|
+
* `eslint.config.ts` of `@maz-ui/node` imports `@maz-ui/eslint-config`, which
|
|
8
|
+
* itself would depend on `@maz-ui/node` for the same logger). Direct usage of
|
|
9
|
+
* `consola` keeps the dependency graph acyclic.
|
|
10
|
+
*/
|
|
11
|
+
type LogLevel = 'silent' | 'error' | 'warning' | 'normal' | 'default' | 'debug' | 'trace' | 'verbose';
|
|
12
|
+
|
|
4
13
|
type MazESLintUserConfig = TypedFlatConfigItem | TypedFlatConfigItem[] | Linter.Config | Linter.Config[];
|
|
14
|
+
type TailwindcssPreset = 'recommended' | 'stylistic' | 'correctness';
|
|
15
|
+
/**
|
|
16
|
+
* Settings forwarded to `eslint-plugin-better-tailwindcss` under
|
|
17
|
+
* `settings['better-tailwindcss']`. See the plugin docs for the canonical
|
|
18
|
+
* meaning of each field.
|
|
19
|
+
*/
|
|
20
|
+
interface MazTailwindcssOptions {
|
|
21
|
+
/**
|
|
22
|
+
* Which preset to load. Each one comes in `*-warn` and `*-error` flavors
|
|
23
|
+
* (defaults match the plugin's defaults: stylistic→warn, correctness→error).
|
|
24
|
+
*
|
|
25
|
+
* @default 'recommended'
|
|
26
|
+
*/
|
|
27
|
+
preset?: TailwindcssPreset;
|
|
28
|
+
/**
|
|
29
|
+
* Tailwind v4: path to the CSS entry file (the one that does
|
|
30
|
+
* `@import "tailwindcss"`, possibly with `prefix(...)`). Required for the
|
|
31
|
+
* plugin to know about your prefix and `@theme` tokens.
|
|
32
|
+
*/
|
|
33
|
+
entryPoint?: string;
|
|
34
|
+
/**
|
|
35
|
+
* Tailwind v3: path to `tailwind.config.{js,ts,cjs,mjs}`. Use `entryPoint`
|
|
36
|
+
* for v4 instead.
|
|
37
|
+
*/
|
|
38
|
+
tailwindConfig?: string;
|
|
39
|
+
/**
|
|
40
|
+
* Tailwind v4: enable detection of custom component classes (`@layer
|
|
41
|
+
* components { … }`) so they are not reported as unknown.
|
|
42
|
+
*
|
|
43
|
+
* @default false
|
|
44
|
+
*/
|
|
45
|
+
detectComponentClasses?: boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Working directory used to resolve `tailwindcss` and the config files
|
|
48
|
+
* above. Useful in monorepos when ESLint runs from the repo root.
|
|
49
|
+
*/
|
|
50
|
+
cwd?: string;
|
|
51
|
+
/**
|
|
52
|
+
* Path to a `tsconfig.json` used to resolve `paths` aliases inside the
|
|
53
|
+
* Tailwind config.
|
|
54
|
+
*/
|
|
55
|
+
tsconfig?: string;
|
|
56
|
+
}
|
|
5
57
|
interface MazESLintOptions extends OptionsConfig {
|
|
6
58
|
/**
|
|
7
|
-
*
|
|
59
|
+
* Tailwind CSS support — wires `eslint-plugin-better-tailwindcss`.
|
|
60
|
+
*
|
|
61
|
+
* - `false` *(default)*: disabled.
|
|
62
|
+
* - `true`: load the `'recommended'` preset with default settings.
|
|
63
|
+
* - `'recommended' | 'stylistic' | 'correctness'`: pick a preset, default
|
|
64
|
+
* settings.
|
|
65
|
+
* - `MazTailwindcssOptions`: pick a preset and pass settings (e.g.
|
|
66
|
+
* `entryPoint` so the plugin learns your v4 prefix).
|
|
67
|
+
*
|
|
8
68
|
* @default false
|
|
9
69
|
*/
|
|
10
|
-
tailwindcss?: boolean;
|
|
70
|
+
tailwindcss?: boolean | TailwindcssPreset | MazTailwindcssOptions;
|
|
11
71
|
/**
|
|
12
72
|
* Enable SonarJS rules for code quality
|
|
13
73
|
* @default true
|
|
@@ -32,6 +92,19 @@ interface MazESLintOptions extends OptionsConfig {
|
|
|
32
92
|
* Additional rules to merge
|
|
33
93
|
*/
|
|
34
94
|
rules?: Partial<Rules>;
|
|
95
|
+
/**
|
|
96
|
+
* Verbosity of the logs emitted while resolving the config. Defaults to
|
|
97
|
+
* `'default'` so the resolved-configuration box is shown when the preset
|
|
98
|
+
* loads. Set to `'silent'` to hide it, or `'debug'` / `'verbose'` to dig
|
|
99
|
+
* deeper.
|
|
100
|
+
*
|
|
101
|
+
* - `'silent'`: nothing is printed.
|
|
102
|
+
* - `'default'` *(default)*: a titled box summarizing the resolved feature
|
|
103
|
+
* toggles.
|
|
104
|
+
* - `'debug'`: also logs each plugin / preset / overrides addition.
|
|
105
|
+
* - `'verbose'`: also logs the final shape (config block count, etc.).
|
|
106
|
+
*/
|
|
107
|
+
logLevel?: LogLevel;
|
|
35
108
|
}
|
|
36
109
|
type MazESLintConfig = ReturnType<typeof antfu>;
|
|
37
110
|
|
|
@@ -68,15 +141,17 @@ declare const sonarjsTestRules: {
|
|
|
68
141
|
};
|
|
69
142
|
|
|
70
143
|
/**
|
|
71
|
-
* Tailwind
|
|
144
|
+
* Files where Tailwind classes commonly live. Exposed for users who want to
|
|
145
|
+
* compose their own config.
|
|
72
146
|
*/
|
|
73
|
-
declare const
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
147
|
+
declare const TAILWINDCSS_DEFAULT_FILES: string[];
|
|
148
|
+
/**
|
|
149
|
+
* Build the flat-config block(s) that wire up
|
|
150
|
+
* `eslint-plugin-better-tailwindcss`. The plugin already ships preset
|
|
151
|
+
* objects with `plugins` + `rules`; we spread them and add `files` plus
|
|
152
|
+
* `settings['better-tailwindcss']` so the user's options reach the plugin.
|
|
153
|
+
*/
|
|
154
|
+
declare function tailwindcssConfigs(preset: TailwindcssPreset, settings: MazTailwindcssOptions): Linter.Config[];
|
|
80
155
|
|
|
81
156
|
declare const vueRules: {
|
|
82
157
|
'vue/custom-event-name-casing': ["error", "kebab-case"];
|
|
@@ -102,5 +177,5 @@ declare const vueRules: {
|
|
|
102
177
|
*/
|
|
103
178
|
declare function defineConfig(options?: MazESLintOptions, ...userConfigs: MazESLintUserConfig[]): MazESLintConfig;
|
|
104
179
|
|
|
105
|
-
export { baseRules, defineConfig, sonarjsRules, sonarjsTestRules,
|
|
106
|
-
export type { MazESLintConfig, MazESLintOptions };
|
|
180
|
+
export { TAILWINDCSS_DEFAULT_FILES, baseRules, defineConfig, sonarjsRules, sonarjsTestRules, tailwindcssConfigs, vueRules };
|
|
181
|
+
export type { MazESLintConfig, MazESLintOptions, MazTailwindcssOptions, TailwindcssPreset };
|
package/dist/index.mjs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { readFileSync } from 'node:fs';
|
|
2
|
-
import { createRequire } from 'node:module';
|
|
3
2
|
import { join } from 'node:path';
|
|
4
3
|
import antfu from '@antfu/eslint-config';
|
|
5
4
|
import { configs } from 'eslint-plugin-sonarjs';
|
|
6
|
-
import tailwind from 'eslint-plugin-tailwindcss';
|
|
7
5
|
import vueA11y from 'eslint-plugin-vuejs-accessibility';
|
|
6
|
+
import { createConsola } from 'consola';
|
|
7
|
+
import betterTailwindcss from 'eslint-plugin-better-tailwindcss';
|
|
8
8
|
|
|
9
9
|
function baseRules(isProduction) {
|
|
10
10
|
return {
|
|
@@ -72,6 +72,29 @@ const GLOBAL_IGNORES = [
|
|
|
72
72
|
"**/components.d.ts"
|
|
73
73
|
];
|
|
74
74
|
|
|
75
|
+
const LEVELS = {
|
|
76
|
+
silent: Number.NEGATIVE_INFINITY,
|
|
77
|
+
error: 0,
|
|
78
|
+
warning: 1,
|
|
79
|
+
normal: 2,
|
|
80
|
+
default: 3,
|
|
81
|
+
debug: 4,
|
|
82
|
+
trace: 5,
|
|
83
|
+
verbose: Number.POSITIVE_INFINITY
|
|
84
|
+
};
|
|
85
|
+
function createLogger() {
|
|
86
|
+
const consola = createConsola();
|
|
87
|
+
return {
|
|
88
|
+
setLevel: (level) => {
|
|
89
|
+
consola.level = LEVELS[level];
|
|
90
|
+
},
|
|
91
|
+
info: (msg) => consola.info(msg),
|
|
92
|
+
debug: (msg) => consola.debug(msg),
|
|
93
|
+
verbose: (msg) => consola.verbose(msg),
|
|
94
|
+
box: (opts) => consola.box(opts)
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
75
98
|
const markdown = {
|
|
76
99
|
files: ["**/*.md/**"],
|
|
77
100
|
rules: {
|
|
@@ -104,17 +127,34 @@ const sonarjsTestRules = {
|
|
|
104
127
|
"sonarjs/no-duplicate-string": "off"
|
|
105
128
|
};
|
|
106
129
|
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
130
|
+
const TAILWINDCSS_FILES = ["**/*.{js,jsx,cjs,mjs,ts,mts,cts,tsx,vue,html,svelte,astro,astrojs,css,scss}"];
|
|
131
|
+
const TAILWINDCSS_DEFAULT_FILES = TAILWINDCSS_FILES;
|
|
132
|
+
function tailwindcssConfigs(preset, settings) {
|
|
133
|
+
const presetConfig = betterTailwindcss.configs[preset];
|
|
134
|
+
const tailwindSettings = {};
|
|
135
|
+
if (settings.entryPoint)
|
|
136
|
+
tailwindSettings.entryPoint = settings.entryPoint;
|
|
137
|
+
if (settings.tailwindConfig)
|
|
138
|
+
tailwindSettings.tailwindConfig = settings.tailwindConfig;
|
|
139
|
+
if (settings.detectComponentClasses !== void 0)
|
|
140
|
+
tailwindSettings.detectComponentClasses = settings.detectComponentClasses;
|
|
141
|
+
if (settings.cwd)
|
|
142
|
+
tailwindSettings.cwd = settings.cwd;
|
|
143
|
+
if (settings.tsconfig)
|
|
144
|
+
tailwindSettings.tsconfig = settings.tsconfig;
|
|
145
|
+
return [{
|
|
146
|
+
...presetConfig,
|
|
147
|
+
files: TAILWINDCSS_FILES,
|
|
148
|
+
settings: {
|
|
149
|
+
"better-tailwindcss": tailwindSettings
|
|
150
|
+
},
|
|
151
|
+
rules: {
|
|
152
|
+
...presetConfig.rules,
|
|
153
|
+
"better-tailwindcss/no-unknown-classes": "off",
|
|
154
|
+
"better-tailwindcss/enforce-consistent-line-wrapping": "off"
|
|
155
|
+
}
|
|
156
|
+
}];
|
|
157
|
+
}
|
|
118
158
|
|
|
119
159
|
const testRules = {
|
|
120
160
|
"max-nested-callbacks": "off"
|
|
@@ -124,6 +164,7 @@ const vueRules = {
|
|
|
124
164
|
"vue/custom-event-name-casing": ["error", "kebab-case"]
|
|
125
165
|
};
|
|
126
166
|
|
|
167
|
+
const TAG = "[@maz-ui/eslint-config]";
|
|
127
168
|
const defaultOptions = {
|
|
128
169
|
formatters: true,
|
|
129
170
|
typescript: true,
|
|
@@ -140,30 +181,89 @@ function getPackageJson() {
|
|
|
140
181
|
return void 0;
|
|
141
182
|
}
|
|
142
183
|
}
|
|
143
|
-
function
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
} catch {
|
|
149
|
-
return 0;
|
|
150
|
-
}
|
|
184
|
+
function hasDependency(pkg, ...names) {
|
|
185
|
+
if (!pkg)
|
|
186
|
+
return false;
|
|
187
|
+
const buckets = [pkg.dependencies, pkg.devDependencies, pkg.peerDependencies];
|
|
188
|
+
return names.some((name) => buckets.some((bucket) => bucket && name in bucket));
|
|
151
189
|
}
|
|
152
|
-
function
|
|
153
|
-
|
|
154
|
-
|
|
190
|
+
function resolveVue(option) {
|
|
191
|
+
if (option === true)
|
|
192
|
+
return { value: true, source: "explicit" };
|
|
193
|
+
if (option === false)
|
|
194
|
+
return { value: false, source: "explicit" };
|
|
195
|
+
return { value: hasDependency(getPackageJson(), "vue", "nuxt"), source: "auto-detected" };
|
|
196
|
+
}
|
|
197
|
+
function resolveTailwindcss(option) {
|
|
198
|
+
if (option === void 0)
|
|
199
|
+
return { value: false, source: "default" };
|
|
200
|
+
if (option === false)
|
|
201
|
+
return { value: false, source: "explicit" };
|
|
202
|
+
if (option === true)
|
|
203
|
+
return { value: { preset: "recommended", settings: {} }, source: "explicit" };
|
|
204
|
+
if (typeof option === "string")
|
|
205
|
+
return { value: { preset: option, settings: {} }, source: "explicit" };
|
|
206
|
+
return { value: { preset: option.preset ?? "recommended", settings: option }, source: "explicit" };
|
|
207
|
+
}
|
|
208
|
+
function resolveOptions(opts, env) {
|
|
209
|
+
const vue = resolveVue(opts.vue);
|
|
210
|
+
const tailwind = resolveTailwindcss(opts.tailwindcss);
|
|
211
|
+
return {
|
|
212
|
+
typescript: opts.typescript !== false,
|
|
213
|
+
formatters: opts.formatters !== false,
|
|
214
|
+
unicorn: opts.unicorn !== false,
|
|
215
|
+
sonarjs: opts.sonarjs !== false,
|
|
216
|
+
vue: vue.value,
|
|
217
|
+
vueSource: vue.source,
|
|
218
|
+
vueAccessibility: opts.vueAccessibility === true,
|
|
219
|
+
tailwindcss: tailwind.value,
|
|
220
|
+
tailwindcssSource: tailwind.source,
|
|
221
|
+
env
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
function formatSourceTag(source) {
|
|
225
|
+
if (source === "auto-detected")
|
|
226
|
+
return " (auto-detected)";
|
|
227
|
+
if (source === "default")
|
|
228
|
+
return " (default)";
|
|
229
|
+
return "";
|
|
230
|
+
}
|
|
231
|
+
function formatResolutionBox(r) {
|
|
232
|
+
const tailwindLabel = r.tailwindcss === false ? "off" : r.tailwindcss.preset;
|
|
233
|
+
const rows = [
|
|
234
|
+
["typescript", String(r.typescript)],
|
|
235
|
+
["vue", `${r.vue}${formatSourceTag(r.vueSource)}`],
|
|
236
|
+
["vueAccessibility", String(r.vueAccessibility)],
|
|
237
|
+
["sonarjs", String(r.sonarjs)],
|
|
238
|
+
["tailwindcss", `${tailwindLabel}${formatSourceTag(r.tailwindcssSource)}`],
|
|
239
|
+
["formatters", String(r.formatters)],
|
|
240
|
+
["unicorn", String(r.unicorn)],
|
|
241
|
+
["env", r.env]
|
|
242
|
+
];
|
|
243
|
+
const labelWidth = Math.max(...rows.map(([k]) => k.length));
|
|
244
|
+
return rows.map(([k, v]) => `${k.padEnd(labelWidth)} ${v}`).join("\n");
|
|
155
245
|
}
|
|
156
246
|
function defineConfig(options = {}, ...userConfigs) {
|
|
247
|
+
const log = createLogger();
|
|
248
|
+
const defaultLogLevel = process.stdout.isTTY ? "default" : "silent";
|
|
249
|
+
log.setLevel(options.logLevel ?? defaultLogLevel);
|
|
157
250
|
const opts = { ...defaultOptions, ...options, ignores: [...GLOBAL_IGNORES, ...options.ignores || []] };
|
|
158
251
|
const env = opts.env || process.env.NODE_ENV || "production";
|
|
252
|
+
const resolved = resolveOptions(opts, env);
|
|
253
|
+
log.box({
|
|
254
|
+
title: "@maz-ui/eslint-config",
|
|
255
|
+
message: formatResolutionBox(resolved),
|
|
256
|
+
style: { borderColor: "cyan", padding: 1 }
|
|
257
|
+
});
|
|
159
258
|
const additionalConfigs = [];
|
|
160
|
-
if (
|
|
259
|
+
if (resolved.vue) {
|
|
161
260
|
additionalConfigs.push({
|
|
162
261
|
files: ["**/*.{js,mjs,cjs,jsx,ts,mts,cts,tsx,vue}"],
|
|
163
262
|
rules: vueRules
|
|
164
263
|
});
|
|
264
|
+
log.debug(`${TAG} Vue: applied vueRules to JS/TS/Vue files`);
|
|
165
265
|
}
|
|
166
|
-
if (
|
|
266
|
+
if (resolved.sonarjs) {
|
|
167
267
|
const sonarjsFiles = ["**/*.{js,mjs,cjs,jsx,ts,mts,cts,tsx,vue}"];
|
|
168
268
|
additionalConfigs.push({
|
|
169
269
|
...configs.recommended,
|
|
@@ -177,8 +277,9 @@ function defineConfig(options = {}, ...userConfigs) {
|
|
|
177
277
|
files: ["**/*.spec.ts", "**/*.test.ts", "**/*.spec.js", "**/*.test.js"],
|
|
178
278
|
rules: sonarjsTestRules
|
|
179
279
|
});
|
|
280
|
+
log.debug(`${TAG} SonarJS: applied recommended preset + ${Object.keys(sonarjsRules).length} extra rules + test-file relaxations`);
|
|
180
281
|
}
|
|
181
|
-
if (
|
|
282
|
+
if (resolved.vueAccessibility) {
|
|
182
283
|
const vueA11yConfigs = vueA11y.configs["flat/recommended"];
|
|
183
284
|
const configsArray = Array.isArray(vueA11yConfigs) ? vueA11yConfigs : [vueA11yConfigs];
|
|
184
285
|
const fixedConfigs = configsArray.map((config) => {
|
|
@@ -199,21 +300,26 @@ function defineConfig(options = {}, ...userConfigs) {
|
|
|
199
300
|
return config;
|
|
200
301
|
});
|
|
201
302
|
additionalConfigs.push(...fixedConfigs);
|
|
303
|
+
log.debug(`${TAG} Vue a11y: applied ${fixedConfigs.length} flat-config block(s) from eslint-plugin-vuejs-accessibility`);
|
|
202
304
|
}
|
|
203
|
-
if (
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
rules: tailwindcssRules
|
|
210
|
-
});
|
|
211
|
-
}
|
|
305
|
+
if (resolved.tailwindcss) {
|
|
306
|
+
const blocks = tailwindcssConfigs(resolved.tailwindcss.preset, resolved.tailwindcss.settings);
|
|
307
|
+
additionalConfigs.push(...blocks);
|
|
308
|
+
const settingKeys = Object.keys(resolved.tailwindcss.settings).filter((k) => k !== "preset");
|
|
309
|
+
const settingsHint = settingKeys.length > 0 ? ` with settings (${settingKeys.join(", ")})` : "";
|
|
310
|
+
log.debug(`${TAG} Tailwind: loaded "${resolved.tailwindcss.preset}" preset${settingsHint}`);
|
|
212
311
|
}
|
|
213
312
|
additionalConfigs.push({
|
|
214
313
|
files: ["**/*.spec.ts", "**/*.test.ts", "**/*.spec.js", "**/*.test.js"],
|
|
215
314
|
rules: testRules
|
|
216
315
|
});
|
|
316
|
+
log.debug(`${TAG} Tests: relaxed rules applied to *.spec.{ts,js} / *.test.{ts,js}`);
|
|
317
|
+
if (options.rules && Object.keys(options.rules).length > 0)
|
|
318
|
+
log.debug(`${TAG} User: merged ${Object.keys(options.rules).length} rule override(s)`);
|
|
319
|
+
if (userConfigs.length > 0)
|
|
320
|
+
log.debug(`${TAG} User: appended ${userConfigs.length} flat-config argument(s)`);
|
|
321
|
+
log.verbose(`${TAG} Final config block count: ${additionalConfigs.length + userConfigs.length + 1} (additional: ${additionalConfigs.length}, user: ${userConfigs.length}, +markdown)`);
|
|
322
|
+
log.verbose(`${TAG} Ignore globs: ${opts.ignores.length}`);
|
|
217
323
|
return antfu({
|
|
218
324
|
formatters: opts.formatters,
|
|
219
325
|
...opts,
|
|
@@ -227,4 +333,4 @@ function defineConfig(options = {}, ...userConfigs) {
|
|
|
227
333
|
}, ...additionalConfigs, ...userConfigs, markdown);
|
|
228
334
|
}
|
|
229
335
|
|
|
230
|
-
export { baseRules, defineConfig, sonarjsRules, sonarjsTestRules,
|
|
336
|
+
export { TAILWINDCSS_DEFAULT_FILES, baseRules, defineConfig, sonarjsRules, sonarjsTestRules, tailwindcssConfigs, vueRules };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@maz-ui/eslint-config",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "5.0.0-beta.1",
|
|
5
5
|
"description": "ESLint configuration for JavaScript/TypeScript projects",
|
|
6
6
|
"author": "Louis Mazel <me@loicmazuel.com>",
|
|
7
7
|
"license": "MIT",
|
|
@@ -43,14 +43,14 @@
|
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
45
|
"@antfu/eslint-config": "^8.2.0",
|
|
46
|
+
"consola": "^3.4.2",
|
|
47
|
+
"eslint-plugin-better-tailwindcss": "^4.5.0",
|
|
46
48
|
"eslint-plugin-format": "^2.0.1",
|
|
47
|
-
"eslint-plugin-sonarjs": "^4.0.
|
|
48
|
-
"eslint-plugin-tailwindcss": "^3.18.3",
|
|
49
|
+
"eslint-plugin-sonarjs": "^4.0.3",
|
|
49
50
|
"eslint-plugin-vuejs-accessibility": "^2.5.0"
|
|
50
51
|
},
|
|
51
52
|
"devDependencies": {
|
|
52
|
-
"
|
|
53
|
-
"eslint": "^10.1.0",
|
|
53
|
+
"eslint": "^10.3.0",
|
|
54
54
|
"unbuild": "^3.6.1"
|
|
55
55
|
},
|
|
56
56
|
"lint-staged": {
|
|
@@ -59,6 +59,7 @@
|
|
|
59
59
|
]
|
|
60
60
|
},
|
|
61
61
|
"scripts": {
|
|
62
|
+
"codegen": "nx build",
|
|
62
63
|
"build": "unbuild",
|
|
63
64
|
"dev": "unbuild --stub",
|
|
64
65
|
"typecheck": "tsc --noEmit --skipLibCheck",
|