@maz-ui/eslint-config 5.0.0-beta.0 → 5.0.0-beta.2
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 +90 -17
- package/dist/index.d.ts +90 -17
- package/dist/index.mjs +149 -51
- package/package.json +4 -10
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,24 +141,24 @@ declare const sonarjsTestRules: {
|
|
|
68
141
|
};
|
|
69
142
|
|
|
70
143
|
/**
|
|
71
|
-
* Tailwind
|
|
72
|
-
*
|
|
73
|
-
* These rules only activate when the user opts in via
|
|
74
|
-
* `defineMazEslintConfig({ tailwindcss: true })` AND is on ESLint 9 +
|
|
75
|
-
* Tailwind v3. The plugin itself does not yet support ESLint 10+ or
|
|
76
|
-
* Tailwind v4 (upstream — uses the removed context.getSourceCode API).
|
|
144
|
+
* Files where Tailwind classes commonly live. Exposed for users who want to
|
|
145
|
+
* compose their own config.
|
|
77
146
|
*/
|
|
78
|
-
declare const
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
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[];
|
|
85
155
|
|
|
86
156
|
declare const vueRules: {
|
|
87
157
|
'vue/custom-event-name-casing': ["error", "kebab-case"];
|
|
88
158
|
};
|
|
159
|
+
declare const vueSfcOnlyRules: {
|
|
160
|
+
'no-useless-assignment': "off";
|
|
161
|
+
};
|
|
89
162
|
|
|
90
163
|
/**
|
|
91
164
|
* Create ESLint configuration for Maz-UI and JavaScript/TypeScript projects
|
|
@@ -107,5 +180,5 @@ declare const vueRules: {
|
|
|
107
180
|
*/
|
|
108
181
|
declare function defineConfig(options?: MazESLintOptions, ...userConfigs: MazESLintUserConfig[]): MazESLintConfig;
|
|
109
182
|
|
|
110
|
-
export { baseRules, defineConfig, sonarjsRules, sonarjsTestRules,
|
|
111
|
-
export type { MazESLintConfig, MazESLintOptions };
|
|
183
|
+
export { TAILWINDCSS_DEFAULT_FILES, baseRules, defineConfig, sonarjsRules, sonarjsTestRules, tailwindcssConfigs, vueRules, vueSfcOnlyRules };
|
|
184
|
+
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,24 +141,24 @@ declare const sonarjsTestRules: {
|
|
|
68
141
|
};
|
|
69
142
|
|
|
70
143
|
/**
|
|
71
|
-
* Tailwind
|
|
72
|
-
*
|
|
73
|
-
* These rules only activate when the user opts in via
|
|
74
|
-
* `defineMazEslintConfig({ tailwindcss: true })` AND is on ESLint 9 +
|
|
75
|
-
* Tailwind v3. The plugin itself does not yet support ESLint 10+ or
|
|
76
|
-
* Tailwind v4 (upstream — uses the removed context.getSourceCode API).
|
|
144
|
+
* Files where Tailwind classes commonly live. Exposed for users who want to
|
|
145
|
+
* compose their own config.
|
|
77
146
|
*/
|
|
78
|
-
declare const
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
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[];
|
|
85
155
|
|
|
86
156
|
declare const vueRules: {
|
|
87
157
|
'vue/custom-event-name-casing': ["error", "kebab-case"];
|
|
88
158
|
};
|
|
159
|
+
declare const vueSfcOnlyRules: {
|
|
160
|
+
'no-useless-assignment': "off";
|
|
161
|
+
};
|
|
89
162
|
|
|
90
163
|
/**
|
|
91
164
|
* Create ESLint configuration for Maz-UI and JavaScript/TypeScript projects
|
|
@@ -107,5 +180,5 @@ declare const vueRules: {
|
|
|
107
180
|
*/
|
|
108
181
|
declare function defineConfig(options?: MazESLintOptions, ...userConfigs: MazESLintUserConfig[]): MazESLintConfig;
|
|
109
182
|
|
|
110
|
-
export { baseRules, defineConfig, sonarjsRules, sonarjsTestRules,
|
|
111
|
-
export type { MazESLintConfig, MazESLintOptions };
|
|
183
|
+
export { TAILWINDCSS_DEFAULT_FILES, baseRules, defineConfig, sonarjsRules, sonarjsTestRules, tailwindcssConfigs, vueRules, vueSfcOnlyRules };
|
|
184
|
+
export type { MazESLintConfig, MazESLintOptions, MazTailwindcssOptions, TailwindcssPreset };
|
package/dist/index.mjs
CHANGED
|
@@ -1,9 +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
5
|
import vueA11y from 'eslint-plugin-vuejs-accessibility';
|
|
6
|
+
import { createConsola } from 'consola';
|
|
7
|
+
import betterTailwindcss from 'eslint-plugin-better-tailwindcss';
|
|
7
8
|
|
|
8
9
|
function baseRules(isProduction) {
|
|
9
10
|
return {
|
|
@@ -71,6 +72,29 @@ const GLOBAL_IGNORES = [
|
|
|
71
72
|
"**/components.d.ts"
|
|
72
73
|
];
|
|
73
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
|
+
|
|
74
98
|
const markdown = {
|
|
75
99
|
files: ["**/*.md/**"],
|
|
76
100
|
rules: {
|
|
@@ -103,17 +127,34 @@ const sonarjsTestRules = {
|
|
|
103
127
|
"sonarjs/no-duplicate-string": "off"
|
|
104
128
|
};
|
|
105
129
|
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
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
|
+
}
|
|
117
158
|
|
|
118
159
|
const testRules = {
|
|
119
160
|
"max-nested-callbacks": "off"
|
|
@@ -122,7 +163,11 @@ const testRules = {
|
|
|
122
163
|
const vueRules = {
|
|
123
164
|
"vue/custom-event-name-casing": ["error", "kebab-case"]
|
|
124
165
|
};
|
|
166
|
+
const vueSfcOnlyRules = {
|
|
167
|
+
"no-useless-assignment": "off"
|
|
168
|
+
};
|
|
125
169
|
|
|
170
|
+
const TAG = "[@maz-ui/eslint-config]";
|
|
126
171
|
const defaultOptions = {
|
|
127
172
|
formatters: true,
|
|
128
173
|
typescript: true,
|
|
@@ -139,39 +184,93 @@ function getPackageJson() {
|
|
|
139
184
|
return void 0;
|
|
140
185
|
}
|
|
141
186
|
}
|
|
142
|
-
function
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
} catch {
|
|
148
|
-
return 0;
|
|
149
|
-
}
|
|
187
|
+
function hasDependency(pkg, ...names) {
|
|
188
|
+
if (!pkg)
|
|
189
|
+
return false;
|
|
190
|
+
const buckets = [pkg.dependencies, pkg.devDependencies, pkg.peerDependencies];
|
|
191
|
+
return names.some((name) => buckets.some((bucket) => bucket && name in bucket));
|
|
150
192
|
}
|
|
151
|
-
function
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
return
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
193
|
+
function resolveVue(option) {
|
|
194
|
+
if (option === true)
|
|
195
|
+
return { value: true, source: "explicit" };
|
|
196
|
+
if (option === false)
|
|
197
|
+
return { value: false, source: "explicit" };
|
|
198
|
+
return { value: hasDependency(getPackageJson(), "vue", "nuxt"), source: "auto-detected" };
|
|
199
|
+
}
|
|
200
|
+
function resolveTailwindcss(option) {
|
|
201
|
+
if (option === void 0)
|
|
202
|
+
return { value: false, source: "default" };
|
|
203
|
+
if (option === false)
|
|
204
|
+
return { value: false, source: "explicit" };
|
|
205
|
+
if (option === true)
|
|
206
|
+
return { value: { preset: "recommended", settings: {} }, source: "explicit" };
|
|
207
|
+
if (typeof option === "string")
|
|
208
|
+
return { value: { preset: option, settings: {} }, source: "explicit" };
|
|
209
|
+
return { value: { preset: option.preset ?? "recommended", settings: option }, source: "explicit" };
|
|
210
|
+
}
|
|
211
|
+
function resolveOptions(opts, env) {
|
|
212
|
+
const vue = resolveVue(opts.vue);
|
|
213
|
+
const tailwind = resolveTailwindcss(opts.tailwindcss);
|
|
214
|
+
return {
|
|
215
|
+
typescript: opts.typescript !== false,
|
|
216
|
+
formatters: opts.formatters !== false,
|
|
217
|
+
unicorn: opts.unicorn !== false,
|
|
218
|
+
sonarjs: opts.sonarjs !== false,
|
|
219
|
+
vue: vue.value,
|
|
220
|
+
vueSource: vue.source,
|
|
221
|
+
vueAccessibility: opts.vueAccessibility === true,
|
|
222
|
+
tailwindcss: tailwind.value,
|
|
223
|
+
tailwindcssSource: tailwind.source,
|
|
224
|
+
env
|
|
225
|
+
};
|
|
159
226
|
}
|
|
160
|
-
function
|
|
161
|
-
|
|
162
|
-
|
|
227
|
+
function formatSourceTag(source) {
|
|
228
|
+
if (source === "auto-detected")
|
|
229
|
+
return " (auto-detected)";
|
|
230
|
+
if (source === "default")
|
|
231
|
+
return " (default)";
|
|
232
|
+
return "";
|
|
233
|
+
}
|
|
234
|
+
function formatResolutionBox(r) {
|
|
235
|
+
const tailwindLabel = r.tailwindcss === false ? "off" : r.tailwindcss.preset;
|
|
236
|
+
const rows = [
|
|
237
|
+
["typescript", String(r.typescript)],
|
|
238
|
+
["vue", `${r.vue}${formatSourceTag(r.vueSource)}`],
|
|
239
|
+
["vueAccessibility", String(r.vueAccessibility)],
|
|
240
|
+
["sonarjs", String(r.sonarjs)],
|
|
241
|
+
["tailwindcss", `${tailwindLabel}${formatSourceTag(r.tailwindcssSource)}`],
|
|
242
|
+
["formatters", String(r.formatters)],
|
|
243
|
+
["unicorn", String(r.unicorn)],
|
|
244
|
+
["env", r.env]
|
|
245
|
+
];
|
|
246
|
+
const labelWidth = Math.max(...rows.map(([k]) => k.length));
|
|
247
|
+
return rows.map(([k, v]) => `${k.padEnd(labelWidth)} ${v}`).join("\n");
|
|
163
248
|
}
|
|
164
249
|
function defineConfig(options = {}, ...userConfigs) {
|
|
250
|
+
const log = createLogger();
|
|
251
|
+
const defaultLogLevel = process.stdout.isTTY ? "default" : "silent";
|
|
252
|
+
log.setLevel(options.logLevel ?? defaultLogLevel);
|
|
165
253
|
const opts = { ...defaultOptions, ...options, ignores: [...GLOBAL_IGNORES, ...options.ignores || []] };
|
|
166
254
|
const env = opts.env || process.env.NODE_ENV || "production";
|
|
255
|
+
const resolved = resolveOptions(opts, env);
|
|
256
|
+
log.box({
|
|
257
|
+
title: "@maz-ui/eslint-config",
|
|
258
|
+
message: formatResolutionBox(resolved),
|
|
259
|
+
style: { borderColor: "cyan", padding: 1 }
|
|
260
|
+
});
|
|
167
261
|
const additionalConfigs = [];
|
|
168
|
-
if (
|
|
262
|
+
if (resolved.vue) {
|
|
169
263
|
additionalConfigs.push({
|
|
170
264
|
files: ["**/*.{js,mjs,cjs,jsx,ts,mts,cts,tsx,vue}"],
|
|
171
265
|
rules: vueRules
|
|
172
266
|
});
|
|
267
|
+
additionalConfigs.push({
|
|
268
|
+
files: ["**/*.vue"],
|
|
269
|
+
rules: vueSfcOnlyRules
|
|
270
|
+
});
|
|
271
|
+
log.debug(`${TAG} Vue: applied vueRules to JS/TS/Vue files + SFC-only overrides to *.vue`);
|
|
173
272
|
}
|
|
174
|
-
if (
|
|
273
|
+
if (resolved.sonarjs) {
|
|
175
274
|
const sonarjsFiles = ["**/*.{js,mjs,cjs,jsx,ts,mts,cts,tsx,vue}"];
|
|
176
275
|
additionalConfigs.push({
|
|
177
276
|
...configs.recommended,
|
|
@@ -185,8 +284,9 @@ function defineConfig(options = {}, ...userConfigs) {
|
|
|
185
284
|
files: ["**/*.spec.ts", "**/*.test.ts", "**/*.spec.js", "**/*.test.js"],
|
|
186
285
|
rules: sonarjsTestRules
|
|
187
286
|
});
|
|
287
|
+
log.debug(`${TAG} SonarJS: applied recommended preset + ${Object.keys(sonarjsRules).length} extra rules + test-file relaxations`);
|
|
188
288
|
}
|
|
189
|
-
if (
|
|
289
|
+
if (resolved.vueAccessibility) {
|
|
190
290
|
const vueA11yConfigs = vueA11y.configs["flat/recommended"];
|
|
191
291
|
const configsArray = Array.isArray(vueA11yConfigs) ? vueA11yConfigs : [vueA11yConfigs];
|
|
192
292
|
const fixedConfigs = configsArray.map((config) => {
|
|
@@ -207,28 +307,26 @@ function defineConfig(options = {}, ...userConfigs) {
|
|
|
207
307
|
return config;
|
|
208
308
|
});
|
|
209
309
|
additionalConfigs.push(...fixedConfigs);
|
|
310
|
+
log.debug(`${TAG} Vue a11y: applied ${fixedConfigs.length} flat-config block(s) from eslint-plugin-vuejs-accessibility`);
|
|
210
311
|
}
|
|
211
|
-
if (
|
|
212
|
-
const
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
if (!tailwindPlugin) {
|
|
218
|
-
console.warn("[maz-eslint-config] opts.tailwindcss is true but eslint-plugin-tailwindcss is not installed. Add it to your devDependencies to enable the Tailwind CSS lint rules.");
|
|
219
|
-
} else {
|
|
220
|
-
const tailwindConfigs = tailwindPlugin.configs?.["flat/recommended"];
|
|
221
|
-
if (Array.isArray(tailwindConfigs)) {
|
|
222
|
-
additionalConfigs.push(...tailwindConfigs);
|
|
223
|
-
}
|
|
224
|
-
additionalConfigs.push({ rules: tailwindcssRules });
|
|
225
|
-
}
|
|
226
|
-
}
|
|
312
|
+
if (resolved.tailwindcss) {
|
|
313
|
+
const blocks = tailwindcssConfigs(resolved.tailwindcss.preset, resolved.tailwindcss.settings);
|
|
314
|
+
additionalConfigs.push(...blocks);
|
|
315
|
+
const settingKeys = Object.keys(resolved.tailwindcss.settings).filter((k) => k !== "preset");
|
|
316
|
+
const settingsHint = settingKeys.length > 0 ? ` with settings (${settingKeys.join(", ")})` : "";
|
|
317
|
+
log.debug(`${TAG} Tailwind: loaded "${resolved.tailwindcss.preset}" preset${settingsHint}`);
|
|
227
318
|
}
|
|
228
319
|
additionalConfigs.push({
|
|
229
320
|
files: ["**/*.spec.ts", "**/*.test.ts", "**/*.spec.js", "**/*.test.js"],
|
|
230
321
|
rules: testRules
|
|
231
322
|
});
|
|
323
|
+
log.debug(`${TAG} Tests: relaxed rules applied to *.spec.{ts,js} / *.test.{ts,js}`);
|
|
324
|
+
if (options.rules && Object.keys(options.rules).length > 0)
|
|
325
|
+
log.debug(`${TAG} User: merged ${Object.keys(options.rules).length} rule override(s)`);
|
|
326
|
+
if (userConfigs.length > 0)
|
|
327
|
+
log.debug(`${TAG} User: appended ${userConfigs.length} flat-config argument(s)`);
|
|
328
|
+
log.verbose(`${TAG} Final config block count: ${additionalConfigs.length + userConfigs.length + 1} (additional: ${additionalConfigs.length}, user: ${userConfigs.length}, +markdown)`);
|
|
329
|
+
log.verbose(`${TAG} Ignore globs: ${opts.ignores.length}`);
|
|
232
330
|
return antfu({
|
|
233
331
|
formatters: opts.formatters,
|
|
234
332
|
...opts,
|
|
@@ -242,4 +340,4 @@ function defineConfig(options = {}, ...userConfigs) {
|
|
|
242
340
|
}, ...additionalConfigs, ...userConfigs, markdown);
|
|
243
341
|
}
|
|
244
342
|
|
|
245
|
-
export { baseRules, defineConfig, sonarjsRules, sonarjsTestRules,
|
|
343
|
+
export { TAILWINDCSS_DEFAULT_FILES, baseRules, defineConfig, sonarjsRules, sonarjsTestRules, tailwindcssConfigs, vueRules, vueSfcOnlyRules };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@maz-ui/eslint-config",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "5.0.0-beta.
|
|
4
|
+
"version": "5.0.0-beta.2",
|
|
5
5
|
"description": "ESLint configuration for JavaScript/TypeScript projects",
|
|
6
6
|
"author": "Louis Mazel <me@loicmazuel.com>",
|
|
7
7
|
"license": "MIT",
|
|
@@ -39,24 +39,18 @@
|
|
|
39
39
|
"node": ">=20.19.0"
|
|
40
40
|
},
|
|
41
41
|
"peerDependencies": {
|
|
42
|
-
"eslint": ">=9.0.0 <11.0.0"
|
|
43
|
-
"eslint-plugin-tailwindcss": "^3.18.0"
|
|
44
|
-
},
|
|
45
|
-
"peerDependenciesMeta": {
|
|
46
|
-
"eslint-plugin-tailwindcss": {
|
|
47
|
-
"optional": true
|
|
48
|
-
}
|
|
42
|
+
"eslint": ">=9.0.0 <11.0.0"
|
|
49
43
|
},
|
|
50
44
|
"dependencies": {
|
|
51
45
|
"@antfu/eslint-config": "^8.2.0",
|
|
46
|
+
"consola": "^3.4.2",
|
|
47
|
+
"eslint-plugin-better-tailwindcss": "^4.5.0",
|
|
52
48
|
"eslint-plugin-format": "^2.0.1",
|
|
53
49
|
"eslint-plugin-sonarjs": "^4.0.3",
|
|
54
50
|
"eslint-plugin-vuejs-accessibility": "^2.5.0"
|
|
55
51
|
},
|
|
56
52
|
"devDependencies": {
|
|
57
|
-
"@types/eslint-plugin-tailwindcss": "^3.17.0",
|
|
58
53
|
"eslint": "^10.3.0",
|
|
59
|
-
"eslint-plugin-tailwindcss": "^3.18.3",
|
|
60
54
|
"unbuild": "^3.6.1"
|
|
61
55
|
},
|
|
62
56
|
"lint-staged": {
|