@dimensional-innovations/tool-config 1.0.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 +646 -0
- package/bin/setup-tool-config.js +675 -0
- package/package.json +168 -0
- package/src/detectors.js +261 -0
- package/src/index.js +64 -0
- package/src/tools/eslint/index.js +287 -0
- package/src/tools/eslint/presets/base.js +82 -0
- package/src/tools/eslint/presets/environments/browser.js +16 -0
- package/src/tools/eslint/presets/environments/node.js +21 -0
- package/src/tools/eslint/presets/environments/universal.js +18 -0
- package/src/tools/eslint/presets/frameworks/angular.js +74 -0
- package/src/tools/eslint/presets/frameworks/astro.js +38 -0
- package/src/tools/eslint/presets/frameworks/node.js +57 -0
- package/src/tools/eslint/presets/frameworks/react.js +76 -0
- package/src/tools/eslint/presets/frameworks/solid.js +45 -0
- package/src/tools/eslint/presets/frameworks/svelte.js +78 -0
- package/src/tools/eslint/presets/frameworks/vanilla.js +16 -0
- package/src/tools/eslint/presets/frameworks/vue.js +125 -0
- package/src/tools/eslint/presets/imports.js +41 -0
- package/src/tools/eslint/presets/typescript.js +131 -0
- package/src/tools/prettier/README.md +398 -0
- package/src/tools/prettier/index.js +114 -0
- package/src/tools/prettier/presets/base.js +36 -0
- package/src/tools/prettier/presets/frameworks/astro.js +15 -0
- package/src/tools/prettier/presets/frameworks/react.js +15 -0
- package/src/tools/prettier/presets/frameworks/svelte.js +22 -0
- package/src/tools/prettier/presets/frameworks/vanilla.js +13 -0
- package/src/tools/prettier/presets/frameworks/vue.js +20 -0
- package/src/tools/prettier/presets/prettierignore.js +56 -0
- package/src/tools/semantic-release/CI_SETUP.md +66 -0
- package/src/tools/semantic-release/README.md +533 -0
- package/src/tools/semantic-release/index.js +130 -0
- package/src/tools/semantic-release/presets/default.js +37 -0
- package/src/tools/semantic-release/presets/library.js +58 -0
- package/src/tools/semantic-release/presets/monorepo.js +48 -0
- package/src/tools/semantic-release/templates/.gitlab-ci.yml +85 -0
- package/src/tools/semantic-release/templates/bitbucket-pipelines.yml +100 -0
- package/src/tools/semantic-release/templates/github-workflow.yml +107 -0
- package/src/tools/stylelint/README.md +425 -0
- package/src/tools/stylelint/index.js +191 -0
- package/src/tools/stylelint/presets/base.js +50 -0
- package/src/tools/stylelint/presets/css-modules.js +43 -0
- package/src/tools/stylelint/presets/frameworks/react.js +18 -0
- package/src/tools/stylelint/presets/frameworks/svelte.js +28 -0
- package/src/tools/stylelint/presets/frameworks/vanilla.js +14 -0
- package/src/tools/stylelint/presets/frameworks/vue.js +38 -0
- package/src/tools/stylelint/presets/scss.js +83 -0
- package/src/tools/stylelint/presets/tailwind.js +49 -0
- package/src/utils/package-reader.js +42 -0
|
@@ -0,0 +1,425 @@
|
|
|
1
|
+
# Stylelint Configuration
|
|
2
|
+
|
|
3
|
+
Framework-aware Stylelint configuration for CSS quality linting across all supported frameworks.
|
|
4
|
+
|
|
5
|
+
## Philosophy
|
|
6
|
+
|
|
7
|
+
This Stylelint configuration focuses on **CSS quality**, not formatting:
|
|
8
|
+
|
|
9
|
+
- **Quality Rules**: Catches errors, enforces best practices, prevents common mistakes
|
|
10
|
+
- **Formatting**: Left to Prettier (never conflicts)
|
|
11
|
+
- **Framework-Aware**: Automatically applies framework-specific rules
|
|
12
|
+
- **Zero Config**: Works out of the box with sensible defaults
|
|
13
|
+
|
|
14
|
+
**Key Principle**: Stylelint is for CSS files and component styles (Vue `<style>`, Svelte `<style>`). CSS-in-JS (styled-components, emotion) should use ESLint plugins instead.
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
The Stylelint tool and core config are included as dependencies. For Vue projects, install optional peer dependencies:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
# Vue projects only
|
|
22
|
+
npm install --save-dev stylelint-config-standard-vue postcss-html
|
|
23
|
+
|
|
24
|
+
# Svelte projects need postcss-html for component parsing
|
|
25
|
+
npm install --save-dev postcss-html
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Usage
|
|
29
|
+
|
|
30
|
+
### Auto-Detection (Recommended)
|
|
31
|
+
|
|
32
|
+
```javascript
|
|
33
|
+
// stylelint.config.js
|
|
34
|
+
import { createConfig } from '@dimensional-innovations/tool-config'
|
|
35
|
+
|
|
36
|
+
export default createConfig('stylelint')
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
The factory automatically detects your framework and applies appropriate rules.
|
|
40
|
+
|
|
41
|
+
### Explicit Framework
|
|
42
|
+
|
|
43
|
+
```javascript
|
|
44
|
+
// stylelint.config.js
|
|
45
|
+
import { createConfig } from '@dimensional-innovations/tool-config'
|
|
46
|
+
|
|
47
|
+
export default createConfig('stylelint', {
|
|
48
|
+
framework: 'vue' // react, vue, svelte, solid, astro, angular, vanilla, node
|
|
49
|
+
})
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### With Custom Rules
|
|
53
|
+
|
|
54
|
+
```javascript
|
|
55
|
+
// stylelint.config.js
|
|
56
|
+
import { createConfig } from '@dimensional-innovations/tool-config'
|
|
57
|
+
|
|
58
|
+
export default createConfig('stylelint', {
|
|
59
|
+
rules: {
|
|
60
|
+
'color-hex-length': 'long',
|
|
61
|
+
'max-nesting-depth': 4
|
|
62
|
+
}
|
|
63
|
+
})
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Framework Support
|
|
67
|
+
|
|
68
|
+
| Framework | Support Level | Features |
|
|
69
|
+
| ----------- | ------------- | ------------------------------------------------------------------ |
|
|
70
|
+
| **Vue** | Full | Scoped styles, `:deep()`, `:global()`, `:slotted()` pseudo-classes |
|
|
71
|
+
| **Svelte** | Full | Component styles, `:global()` pseudo-class |
|
|
72
|
+
| **React** | CSS Modules | `:global()`, `:local()`, `:export`, `:import` pseudo-classes |
|
|
73
|
+
| **Solid** | CSS Modules | Same as React (CSS Modules support) |
|
|
74
|
+
| **Angular** | Base | Standard CSS linting |
|
|
75
|
+
| **Astro** | Base | Standard CSS linting |
|
|
76
|
+
| **Vanilla** | Full | Standard CSS linting |
|
|
77
|
+
| **Node.js** | N/A | Not applicable (no CSS in Node.js backends) |
|
|
78
|
+
|
|
79
|
+
### When to Use Stylelint
|
|
80
|
+
|
|
81
|
+
**Use Stylelint for:**
|
|
82
|
+
|
|
83
|
+
- Separate CSS files (`styles.css`)
|
|
84
|
+
- Vue Single File Components (`<style>` blocks)
|
|
85
|
+
- Svelte components (`<style>` blocks)
|
|
86
|
+
- CSS Modules (`.module.css`)
|
|
87
|
+
- Sass/SCSS files
|
|
88
|
+
|
|
89
|
+
**Don't use Stylelint for:**
|
|
90
|
+
|
|
91
|
+
- CSS-in-JS (styled-components, emotion) → Use ESLint plugins
|
|
92
|
+
- Inline styles in JSX → Use ESLint plugins
|
|
93
|
+
- Tailwind classes → Not linted (utility-first)
|
|
94
|
+
|
|
95
|
+
## Base Configuration
|
|
96
|
+
|
|
97
|
+
All frameworks start with these base rules:
|
|
98
|
+
|
|
99
|
+
### Color Rules
|
|
100
|
+
|
|
101
|
+
- `color-hex-length`: Prefer short hex colors (`#fff` not `#ffffff`)
|
|
102
|
+
- `color-named`: Disallow named colors (use hex/rgb instead)
|
|
103
|
+
|
|
104
|
+
### Property Rules
|
|
105
|
+
|
|
106
|
+
- `declaration-block-no-redundant-longhand-properties`: Use shorthands where possible
|
|
107
|
+
- `shorthand-property-no-redundant-values`: Avoid redundant values in shorthands
|
|
108
|
+
|
|
109
|
+
### Selector Rules
|
|
110
|
+
|
|
111
|
+
- `selector-max-id`: No ID selectors (use classes)
|
|
112
|
+
- `selector-no-qualifying-type`: Don't qualify selectors with type (`div.foo` → `.foo`)
|
|
113
|
+
- `selector-class-pattern`: Enforce BEM or kebab-case naming
|
|
114
|
+
|
|
115
|
+
### Structure Rules
|
|
116
|
+
|
|
117
|
+
- `max-nesting-depth`: Maximum 3 levels of nesting
|
|
118
|
+
- `no-descending-specificity`: Disabled (too strict for real-world CSS)
|
|
119
|
+
|
|
120
|
+
### Tailwind Support
|
|
121
|
+
|
|
122
|
+
Automatically ignores Tailwind at-rules:
|
|
123
|
+
|
|
124
|
+
- `@tailwind`
|
|
125
|
+
- `@apply`
|
|
126
|
+
- `@variants`
|
|
127
|
+
- `@responsive`
|
|
128
|
+
- `@screen`
|
|
129
|
+
|
|
130
|
+
## Framework-Specific Features
|
|
131
|
+
|
|
132
|
+
### Vue (Scoped Styles)
|
|
133
|
+
|
|
134
|
+
```vue
|
|
135
|
+
<style scoped>
|
|
136
|
+
/* Standard scoped styles work */
|
|
137
|
+
.button {
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/* Deep selectors supported */
|
|
141
|
+
:deep(.child) {
|
|
142
|
+
}
|
|
143
|
+
:global(.utility) {
|
|
144
|
+
}
|
|
145
|
+
:slotted(span) {
|
|
146
|
+
}
|
|
147
|
+
</style>
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
**Configuration**: Extends `stylelint-config-standard-vue`, uses `postcss-html` parser.
|
|
151
|
+
|
|
152
|
+
### Svelte (Component Styles)
|
|
153
|
+
|
|
154
|
+
```svelte
|
|
155
|
+
<style>
|
|
156
|
+
/* Component-scoped by default */
|
|
157
|
+
.button { }
|
|
158
|
+
|
|
159
|
+
/* Global styles supported */
|
|
160
|
+
:global(.utility) { }
|
|
161
|
+
</style>
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
**Configuration**: Uses `postcss-html` parser for `.svelte` files.
|
|
165
|
+
|
|
166
|
+
### React/Solid (CSS Modules)
|
|
167
|
+
|
|
168
|
+
```css
|
|
169
|
+
/* styles.module.css */
|
|
170
|
+
.button {
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
:global(.utility) {
|
|
174
|
+
}
|
|
175
|
+
:local(.scoped) {
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/* Exports for JavaScript */
|
|
179
|
+
:export {
|
|
180
|
+
primaryColor: blue;
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
**Configuration**: Supports CSS Modules pseudo-classes (`:global`, `:local`, `:export`, `:import`).
|
|
185
|
+
|
|
186
|
+
### Angular/Astro/Vanilla
|
|
187
|
+
|
|
188
|
+
Standard CSS linting with base rules. No framework-specific features needed.
|
|
189
|
+
|
|
190
|
+
## Package.json Scripts
|
|
191
|
+
|
|
192
|
+
Add these scripts to your `package.json`:
|
|
193
|
+
|
|
194
|
+
```json
|
|
195
|
+
{
|
|
196
|
+
"scripts": {
|
|
197
|
+
"style": "stylelint '**/*.css'",
|
|
198
|
+
"style:fix": "stylelint '**/*.css' --fix"
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### Framework-Specific Patterns
|
|
204
|
+
|
|
205
|
+
**Vue**:
|
|
206
|
+
|
|
207
|
+
```json
|
|
208
|
+
{
|
|
209
|
+
"scripts": {
|
|
210
|
+
"style": "stylelint '**/*.css' '**/*.vue'",
|
|
211
|
+
"style:fix": "stylelint '**/*.css' '**/*.vue' --fix"
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
**Svelte**:
|
|
217
|
+
|
|
218
|
+
```json
|
|
219
|
+
{
|
|
220
|
+
"scripts": {
|
|
221
|
+
"style": "stylelint '**/*.css' '**/*.svelte'",
|
|
222
|
+
"style:fix": "stylelint '**/*.css' '**/*.svelte' --fix"
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
**React/Angular/Vanilla**:
|
|
228
|
+
|
|
229
|
+
```json
|
|
230
|
+
{
|
|
231
|
+
"scripts": {
|
|
232
|
+
"style": "stylelint '**/*.css'",
|
|
233
|
+
"style:fix": "stylelint '**/*.css' --fix'
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
## Integration with Other Tools
|
|
239
|
+
|
|
240
|
+
### Stylelint + Prettier
|
|
241
|
+
|
|
242
|
+
No conflicts! They work together perfectly:
|
|
243
|
+
|
|
244
|
+
- **Stylelint**: CSS quality (errors, best practices)
|
|
245
|
+
- **Prettier**: CSS formatting (indentation, line breaks, spacing)
|
|
246
|
+
|
|
247
|
+
Run them sequentially:
|
|
248
|
+
|
|
249
|
+
```bash
|
|
250
|
+
npm run style && npm run prettier:fix
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### Stylelint + ESLint
|
|
254
|
+
|
|
255
|
+
No conflicts! Different file types:
|
|
256
|
+
|
|
257
|
+
- **ESLint**: JavaScript/TypeScript files
|
|
258
|
+
- **Stylelint**: CSS files and component styles
|
|
259
|
+
- **CSS-in-JS**: Use ESLint plugins (not Stylelint)
|
|
260
|
+
|
|
261
|
+
### VSCode Integration
|
|
262
|
+
|
|
263
|
+
Install the Stylelint extension:
|
|
264
|
+
|
|
265
|
+
```json
|
|
266
|
+
{
|
|
267
|
+
"stylelint.validate": ["css", "scss", "vue", "svelte"],
|
|
268
|
+
"editor.codeActionsOnSave": {
|
|
269
|
+
"source.fixAll.stylelint": "explicit"
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
## Common Overrides
|
|
275
|
+
|
|
276
|
+
### Allow Deeper Nesting
|
|
277
|
+
|
|
278
|
+
```javascript
|
|
279
|
+
export default createConfig('stylelint', {
|
|
280
|
+
rules: {
|
|
281
|
+
'max-nesting-depth': 5
|
|
282
|
+
}
|
|
283
|
+
})
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
### Allow ID Selectors
|
|
287
|
+
|
|
288
|
+
```javascript
|
|
289
|
+
export default createConfig('stylelint', {
|
|
290
|
+
rules: {
|
|
291
|
+
'selector-max-id': 2 // Allow up to 2 IDs
|
|
292
|
+
}
|
|
293
|
+
})
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
### Custom Class Naming Pattern
|
|
297
|
+
|
|
298
|
+
```javascript
|
|
299
|
+
export default createConfig('stylelint', {
|
|
300
|
+
rules: {
|
|
301
|
+
'selector-class-pattern': '^[a-z][a-zA-Z0-9]+$' // camelCase only
|
|
302
|
+
}
|
|
303
|
+
})
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
### Disable Specific Rule
|
|
307
|
+
|
|
308
|
+
```javascript
|
|
309
|
+
export default createConfig('stylelint', {
|
|
310
|
+
rules: {
|
|
311
|
+
'color-named': null // Allow named colors
|
|
312
|
+
}
|
|
313
|
+
})
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
## Troubleshooting
|
|
317
|
+
|
|
318
|
+
### "Cannot find module 'stylelint-config-standard-vue'"
|
|
319
|
+
|
|
320
|
+
**Vue projects only**: Install the optional peer dependency:
|
|
321
|
+
|
|
322
|
+
```bash
|
|
323
|
+
npm install --save-dev stylelint-config-standard-vue postcss-html
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
### "Cannot find module 'postcss-html'"
|
|
327
|
+
|
|
328
|
+
**Vue/Svelte projects**: Install the parser:
|
|
329
|
+
|
|
330
|
+
```bash
|
|
331
|
+
npm install --save-dev postcss-html
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
### Stylelint Not Linting .vue Files
|
|
335
|
+
|
|
336
|
+
Make sure your script includes `.vue` files:
|
|
337
|
+
|
|
338
|
+
```json
|
|
339
|
+
{
|
|
340
|
+
"scripts": {
|
|
341
|
+
"style": "stylelint '**/*.css' '**/*.vue'"
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
### Conflicts with Prettier
|
|
347
|
+
|
|
348
|
+
This shouldn't happen! Our Stylelint config focuses on quality, not formatting. If you encounter conflicts:
|
|
349
|
+
|
|
350
|
+
1. Check that Prettier is formatting CSS (it should be)
|
|
351
|
+
2. Disable formatting-related Stylelint rules:
|
|
352
|
+
```javascript
|
|
353
|
+
export default createConfig('stylelint', {
|
|
354
|
+
rules: {
|
|
355
|
+
indentation: null,
|
|
356
|
+
'string-quotes': null
|
|
357
|
+
}
|
|
358
|
+
})
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
### "Unknown rule" Errors
|
|
362
|
+
|
|
363
|
+
Make sure you're using Stylelint 16+:
|
|
364
|
+
|
|
365
|
+
```bash
|
|
366
|
+
npm install --save-dev stylelint@^16.0.0
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
## Rule Philosophy
|
|
370
|
+
|
|
371
|
+
### Error vs Warning
|
|
372
|
+
|
|
373
|
+
**Error (Red)**: Will break your CSS or violate critical best practices
|
|
374
|
+
|
|
375
|
+
- `color-named`: Named colors are unreliable across browsers
|
|
376
|
+
- `selector-max-id`: IDs have high specificity and cause maintenance issues
|
|
377
|
+
- `max-nesting-depth`: Deep nesting makes CSS hard to maintain
|
|
378
|
+
|
|
379
|
+
**Warning (Yellow)**: Not used in this config (all rules are errors)
|
|
380
|
+
|
|
381
|
+
**Off**: Rule disabled (conflicts with Prettier or too opinionated)
|
|
382
|
+
|
|
383
|
+
### Why We Don't Use Warnings
|
|
384
|
+
|
|
385
|
+
Warnings create ambiguity. Either something is wrong (error) or it's acceptable (off). Our approach:
|
|
386
|
+
|
|
387
|
+
- **Error**: Fix this (quality/correctness issue)
|
|
388
|
+
- **Off**: We don't care about this (formatting/style)
|
|
389
|
+
|
|
390
|
+
## Examples
|
|
391
|
+
|
|
392
|
+
See working examples in the `examples/` directory:
|
|
393
|
+
|
|
394
|
+
- [examples/vue-app/](../../examples/vue-app/) - Vue 3 with scoped styles
|
|
395
|
+
- [examples/svelte-app/](../../examples/svelte-app/) - Svelte 5 with component styles
|
|
396
|
+
- [examples/react-app/](../../examples/react-app/) - React with CSS Modules
|
|
397
|
+
- [examples/angular-app/](../../examples/angular-app/) - Angular with standard CSS
|
|
398
|
+
- [examples/vanilla-js/](../../examples/vanilla-js/) - Vanilla JS with standard CSS
|
|
399
|
+
|
|
400
|
+
## API Reference
|
|
401
|
+
|
|
402
|
+
### createConfig(tool, options)
|
|
403
|
+
|
|
404
|
+
**Parameters**:
|
|
405
|
+
|
|
406
|
+
- `tool` (string): Must be `'stylelint'`
|
|
407
|
+
- `options` (object):
|
|
408
|
+
- `framework` (string): `'auto'` (default) | `'react'` | `'vue'` | `'svelte'` | `'solid'` | `'astro'` | `'angular'` | `'vanilla'` | `'node'`
|
|
409
|
+
- `cwd` (string): Working directory for auto-detection (default: `process.cwd()`)
|
|
410
|
+
- `rules` (object): Rule overrides
|
|
411
|
+
- `extends` (string|array): Additional configs to extend
|
|
412
|
+
- `overrides` (array): File-specific overrides
|
|
413
|
+
|
|
414
|
+
**Returns**: Stylelint configuration object
|
|
415
|
+
|
|
416
|
+
## Related Documentation
|
|
417
|
+
|
|
418
|
+
- [Stylelint Official Docs](https://stylelint.io/)
|
|
419
|
+
- [stylelint-config-standard](https://github.com/stylelint/stylelint-config-standard)
|
|
420
|
+
- [stylelint-config-standard-vue](https://github.com/ota-meshi/stylelint-config-standard-vue)
|
|
421
|
+
- [postcss-html](https://github.com/gucong3000/postcss-html)
|
|
422
|
+
|
|
423
|
+
## License
|
|
424
|
+
|
|
425
|
+
MIT
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stylelint configuration factory
|
|
3
|
+
*
|
|
4
|
+
* Creates Stylelint configurations with framework-aware defaults for CSS linting.
|
|
5
|
+
*
|
|
6
|
+
* Note: Stylelint is for CSS files and component styles (Vue, Svelte).
|
|
7
|
+
* CSS-in-JS (React styled-components, emotion) should use ESLint plugins instead.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { autoDetect, detectCssType } from '../../detectors.js'
|
|
11
|
+
|
|
12
|
+
import basePreset from './presets/base.js'
|
|
13
|
+
import cssModulesPreset from './presets/css-modules.js'
|
|
14
|
+
import reactPreset from './presets/frameworks/react.js'
|
|
15
|
+
import sveltePreset from './presets/frameworks/svelte.js'
|
|
16
|
+
import vuePreset from './presets/frameworks/vue.js'
|
|
17
|
+
import scssPreset from './presets/scss.js'
|
|
18
|
+
import tailwindPreset from './presets/tailwind.js'
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Merge framework preset into config
|
|
22
|
+
* @param {Object} config - Base config
|
|
23
|
+
* @param {Object} preset - Framework preset
|
|
24
|
+
* @returns {void}
|
|
25
|
+
*/
|
|
26
|
+
function mergePreset(config, preset) {
|
|
27
|
+
if (preset.extends) {
|
|
28
|
+
config.extends = [...(config.extends || []), ...preset.extends]
|
|
29
|
+
}
|
|
30
|
+
if (preset.overrides) {
|
|
31
|
+
config.overrides = [...(config.overrides || []), ...preset.overrides]
|
|
32
|
+
}
|
|
33
|
+
if (preset.rules) {
|
|
34
|
+
config.rules = { ...config.rules, ...preset.rules }
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Apply user overrides to config
|
|
40
|
+
* @param {Object} config - Current config
|
|
41
|
+
* @param {Object} userOverrides - User-provided overrides
|
|
42
|
+
* @returns {void}
|
|
43
|
+
*/
|
|
44
|
+
function applyUserOverrides(config, userOverrides) {
|
|
45
|
+
// Handle arrays (extends, plugins, overrides)
|
|
46
|
+
if (userOverrides.extends) {
|
|
47
|
+
const userExtends = Array.isArray(userOverrides.extends)
|
|
48
|
+
? userOverrides.extends
|
|
49
|
+
: [userOverrides.extends]
|
|
50
|
+
config.extends = [...(config.extends || []), ...userExtends]
|
|
51
|
+
delete userOverrides.extends
|
|
52
|
+
}
|
|
53
|
+
if (userOverrides.plugins) {
|
|
54
|
+
const userPlugins = Array.isArray(userOverrides.plugins)
|
|
55
|
+
? userOverrides.plugins
|
|
56
|
+
: [userOverrides.plugins]
|
|
57
|
+
config.plugins = [...(config.plugins || []), ...userPlugins]
|
|
58
|
+
delete userOverrides.plugins
|
|
59
|
+
}
|
|
60
|
+
if (userOverrides.overrides) {
|
|
61
|
+
const userOverridesArray = Array.isArray(userOverrides.overrides)
|
|
62
|
+
? userOverrides.overrides
|
|
63
|
+
: [userOverrides.overrides]
|
|
64
|
+
config.overrides = [...(config.overrides || []), ...userOverridesArray]
|
|
65
|
+
delete userOverrides.overrides
|
|
66
|
+
}
|
|
67
|
+
if (userOverrides.rules) {
|
|
68
|
+
config.rules = { ...config.rules, ...userOverrides.rules }
|
|
69
|
+
delete userOverrides.rules
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Merge remaining overrides
|
|
73
|
+
Object.assign(config, userOverrides)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Create a Stylelint configuration
|
|
78
|
+
*
|
|
79
|
+
* @param {Object} options - Configuration options
|
|
80
|
+
* @param {string} [options.framework='auto'] - Framework to configure for
|
|
81
|
+
* @param {string|Object} [options.cssType='auto'] - CSS type ('auto', 'css', 'scss', or detection object)
|
|
82
|
+
* @param {string} [options.cwd=process.cwd()] - Working directory for auto-detection
|
|
83
|
+
* @param {Object} [options.rules] - User rule overrides
|
|
84
|
+
* @param {Array|string} [options.extends] - Additional configs to extend
|
|
85
|
+
* @param {Array} [options.overrides] - File-specific overrides
|
|
86
|
+
* @returns {Object} Stylelint configuration object
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* // Auto-detect framework
|
|
90
|
+
* export default createStylelintConfig();
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* // Explicit framework
|
|
94
|
+
* export default createStylelintConfig({ framework: 'vue' });
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* // Explicit CSS type
|
|
98
|
+
* export default createStylelintConfig({ cssType: 'scss' });
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* // With overrides
|
|
102
|
+
* export default createStylelintConfig({
|
|
103
|
+
* framework: 'vue',
|
|
104
|
+
* cssType: 'scss',
|
|
105
|
+
* rules: {
|
|
106
|
+
* 'color-hex-length': 'long'
|
|
107
|
+
* }
|
|
108
|
+
* });
|
|
109
|
+
*/
|
|
110
|
+
export function createStylelintConfig(options = {}) {
|
|
111
|
+
const {
|
|
112
|
+
framework: explicitFramework = 'auto',
|
|
113
|
+
cssType: explicitCssType = 'auto',
|
|
114
|
+
cwd = process.cwd(),
|
|
115
|
+
...userOverrides
|
|
116
|
+
} = options
|
|
117
|
+
|
|
118
|
+
// Auto-detect framework if needed
|
|
119
|
+
const framework = explicitFramework === 'auto' ? autoDetect(cwd).framework : explicitFramework
|
|
120
|
+
|
|
121
|
+
// Auto-detect CSS type if needed
|
|
122
|
+
const cssType = explicitCssType === 'auto' ? detectCssType(cwd) : explicitCssType
|
|
123
|
+
|
|
124
|
+
// Start with appropriate base configuration (SCSS or plain CSS)
|
|
125
|
+
const config =
|
|
126
|
+
cssType?.preprocessor === 'scss' || cssType === 'scss'
|
|
127
|
+
? { ...scssPreset, customSyntax: 'postcss-scss' }
|
|
128
|
+
: { ...basePreset }
|
|
129
|
+
|
|
130
|
+
// Apply Tailwind preset if detected
|
|
131
|
+
if (cssType?.tailwind) {
|
|
132
|
+
mergePreset(config, tailwindPreset)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// CSS Modules support (for React/Next.js projects)
|
|
136
|
+
if ((framework === 'react' || framework === 'solid') && !cssType?.tailwind) {
|
|
137
|
+
mergePreset(config, cssModulesPreset)
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Build CSS type description
|
|
141
|
+
let cssTypeDesc = cssType?.preprocessor === 'scss' ? 'SCSS' : 'CSS'
|
|
142
|
+
if (cssType?.tailwind) cssTypeDesc += ' + Tailwind'
|
|
143
|
+
if ((framework === 'react' || framework === 'solid') && !cssType?.tailwind) {
|
|
144
|
+
cssTypeDesc += ' Modules'
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Apply framework-specific preset
|
|
148
|
+
switch (framework) {
|
|
149
|
+
case 'vue': {
|
|
150
|
+
mergePreset(config, vuePreset)
|
|
151
|
+
console.warn(`🎨 Stylelint: Detected Vue.js - linting .vue component styles (${cssTypeDesc})`)
|
|
152
|
+
break
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
case 'svelte': {
|
|
156
|
+
mergePreset(config, sveltePreset)
|
|
157
|
+
console.warn(
|
|
158
|
+
`🎨 Stylelint: Detected Svelte - linting .svelte component styles (${cssTypeDesc})`
|
|
159
|
+
)
|
|
160
|
+
break
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
case 'react':
|
|
164
|
+
case 'solid': {
|
|
165
|
+
mergePreset(config, reactPreset)
|
|
166
|
+
console.warn(
|
|
167
|
+
`🎨 Stylelint: Detected ${framework} - linting ${cssTypeDesc} (CSS-in-JS uses ESLint)`
|
|
168
|
+
)
|
|
169
|
+
break
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
case 'angular':
|
|
173
|
+
case 'node':
|
|
174
|
+
case 'vanilla':
|
|
175
|
+
case 'astro': {
|
|
176
|
+
console.warn(`🎨 Stylelint: Detected ${framework} - linting ${cssTypeDesc} files`)
|
|
177
|
+
break
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
default: {
|
|
181
|
+
console.warn(`⚠️ Unknown framework "${framework}", using base ${cssTypeDesc} linting`)
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Apply user overrides
|
|
186
|
+
applyUserOverrides(config, userOverrides)
|
|
187
|
+
|
|
188
|
+
return config
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export default createStylelintConfig
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base Stylelint preset
|
|
3
|
+
*
|
|
4
|
+
* Standard CSS linting rules for all projects.
|
|
5
|
+
* Focuses on code quality and best practices, NOT formatting (that's Prettier's job).
|
|
6
|
+
*
|
|
7
|
+
* Key principles:
|
|
8
|
+
* - Use modern CSS practices
|
|
9
|
+
* - Avoid common mistakes
|
|
10
|
+
* - Maintain consistency
|
|
11
|
+
* - Don't fight with Prettier
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
export default {
|
|
15
|
+
extends: ['stylelint-config-standard'],
|
|
16
|
+
|
|
17
|
+
rules: {
|
|
18
|
+
// Color rules
|
|
19
|
+
'color-hex-length': 'short',
|
|
20
|
+
'color-named': 'never',
|
|
21
|
+
|
|
22
|
+
// Property rules
|
|
23
|
+
'declaration-block-no-redundant-longhand-properties': true,
|
|
24
|
+
'shorthand-property-no-redundant-values': true,
|
|
25
|
+
|
|
26
|
+
// Selector rules
|
|
27
|
+
'selector-max-id': 0,
|
|
28
|
+
'selector-no-qualifying-type': true,
|
|
29
|
+
'selector-class-pattern': [
|
|
30
|
+
'^[a-z]([a-z0-9-]+)?(__([a-z0-9]+-?)+)?(--([a-z0-9]+-?)+){0,2}$',
|
|
31
|
+
{
|
|
32
|
+
message: 'Expected class selector to be kebab-case or BEM format'
|
|
33
|
+
}
|
|
34
|
+
],
|
|
35
|
+
|
|
36
|
+
// Nesting
|
|
37
|
+
'max-nesting-depth': 3,
|
|
38
|
+
|
|
39
|
+
// Specificity
|
|
40
|
+
'no-descending-specificity': null,
|
|
41
|
+
|
|
42
|
+
// At-rules
|
|
43
|
+
'at-rule-no-unknown': [
|
|
44
|
+
true,
|
|
45
|
+
{
|
|
46
|
+
ignoreAtRules: ['tailwind', 'apply', 'variants', 'responsive', 'screen']
|
|
47
|
+
}
|
|
48
|
+
]
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CSS Modules Stylelint preset
|
|
3
|
+
*
|
|
4
|
+
* Configuration for projects using CSS Modules.
|
|
5
|
+
* Allows CSS Modules-specific pseudo-classes and conventions.
|
|
6
|
+
*
|
|
7
|
+
* Key principles:
|
|
8
|
+
* - Support :global() and :local() pseudo-classes
|
|
9
|
+
* - Allow composition with composes
|
|
10
|
+
* - Support @value imports
|
|
11
|
+
* - Work alongside regular CSS/SCSS
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
export default {
|
|
15
|
+
rules: {
|
|
16
|
+
// Allow CSS Modules pseudo-classes
|
|
17
|
+
'selector-pseudo-class-no-unknown': [
|
|
18
|
+
true,
|
|
19
|
+
{
|
|
20
|
+
ignorePseudoClasses: ['global', 'local', 'export', 'import']
|
|
21
|
+
}
|
|
22
|
+
],
|
|
23
|
+
|
|
24
|
+
// Allow @value (CSS Modules constants)
|
|
25
|
+
'at-rule-no-unknown': [
|
|
26
|
+
true,
|
|
27
|
+
{
|
|
28
|
+
ignoreAtRules: ['value']
|
|
29
|
+
}
|
|
30
|
+
],
|
|
31
|
+
|
|
32
|
+
// Allow 'composes' property (CSS Modules composition)
|
|
33
|
+
'property-no-unknown': [
|
|
34
|
+
true,
|
|
35
|
+
{
|
|
36
|
+
ignoreProperties: ['composes', 'compose-with']
|
|
37
|
+
}
|
|
38
|
+
],
|
|
39
|
+
|
|
40
|
+
// CSS Modules often use camelCase
|
|
41
|
+
'selector-class-pattern': null // Disable pattern check for modules
|
|
42
|
+
}
|
|
43
|
+
}
|