@dimensional-innovations/tool-config 1.0.0 → 1.2.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/README.md +88 -0
- package/bin/setup-tool-config.js +98 -25
- package/package.json +1 -1
- package/src/tools/eslint/index.js +2 -7
- package/src/tools/eslint/presets/base.js +2 -2
- package/src/tools/eslint/presets/frameworks/vue.js +105 -96
- package/src/tools/eslint/presets/imports.js +7 -1
- package/src/tools/eslint/presets/typescript.js +15 -4
- package/src/tools/prettier/index.js +18 -0
- package/src/tools/stylelint/index.js +4 -0
- package/src/utils/ignore-patterns.js +156 -0
package/README.md
CHANGED
|
@@ -541,8 +541,96 @@ export default [
|
|
|
541
541
|
]
|
|
542
542
|
```
|
|
543
543
|
|
|
544
|
+
## Ignoring Files
|
|
545
|
+
|
|
546
|
+
All tools automatically ignore common build outputs and generated files to prevent unnecessary linting and formatting. This happens automatically when you create a config - no manual setup required.
|
|
547
|
+
|
|
548
|
+
### What Gets Ignored
|
|
549
|
+
|
|
550
|
+
**Common directories** (all tools):
|
|
551
|
+
|
|
552
|
+
- `node_modules/` - Dependencies
|
|
553
|
+
- `dist/`, `build/`, `out/` - Build outputs
|
|
554
|
+
- `coverage/` - Test coverage reports
|
|
555
|
+
- `.nyc_output/` - NYC coverage data
|
|
556
|
+
|
|
557
|
+
**Framework build outputs** (all tools):
|
|
558
|
+
|
|
559
|
+
- `.next/` - Next.js
|
|
560
|
+
- `.nuxt/`, `.output/` - Nuxt
|
|
561
|
+
- `.svelte-kit/` - SvelteKit
|
|
562
|
+
- `.vite/` - Vite cache
|
|
563
|
+
- `.cache/`, `.parcel-cache/`, `.turbo/` - Build caches
|
|
564
|
+
|
|
565
|
+
**Generated files** (Prettier only):
|
|
566
|
+
|
|
567
|
+
- Lock files (`package-lock.json`, `yarn.lock`, `pnpm-lock.yaml`)
|
|
568
|
+
- `CHANGELOG.md` (auto-generated by semantic-release)
|
|
569
|
+
|
|
570
|
+
### How It Works
|
|
571
|
+
|
|
572
|
+
**ESLint**: Uses runtime `ignores` array in flat config
|
|
573
|
+
**Stylelint**: Uses runtime `ignoreFiles` property in config
|
|
574
|
+
**Prettier**: Auto-generates `.prettierignore` file on first run
|
|
575
|
+
|
|
576
|
+
### Customizing Ignore Patterns
|
|
577
|
+
|
|
578
|
+
**ESLint** - Add custom ignores:
|
|
579
|
+
|
|
580
|
+
```javascript
|
|
581
|
+
export default await createConfig('eslint', {
|
|
582
|
+
ignorePaths: ['generated/**', 'legacy/**']
|
|
583
|
+
})
|
|
584
|
+
```
|
|
585
|
+
|
|
586
|
+
**Stylelint** - Extend ignoreFiles:
|
|
587
|
+
|
|
588
|
+
```javascript
|
|
589
|
+
export default createConfig('stylelint', {
|
|
590
|
+
ignoreFiles: ['**/*.min.css', 'vendor/**']
|
|
591
|
+
})
|
|
592
|
+
```
|
|
593
|
+
|
|
594
|
+
**Prettier** - Edit `.prettierignore` file:
|
|
595
|
+
|
|
596
|
+
```
|
|
597
|
+
# Custom ignores
|
|
598
|
+
generated/
|
|
599
|
+
legacy/
|
|
600
|
+
```
|
|
601
|
+
|
|
602
|
+
### Verifying Ignore Patterns
|
|
603
|
+
|
|
604
|
+
Check what files are being processed:
|
|
605
|
+
|
|
606
|
+
```bash
|
|
607
|
+
# ESLint
|
|
608
|
+
npx eslint --debug . 2>&1 | grep "Ignored"
|
|
609
|
+
|
|
610
|
+
# Stylelint
|
|
611
|
+
npx stylelint "**/*.css" --formatter verbose
|
|
612
|
+
|
|
613
|
+
# Prettier
|
|
614
|
+
npx prettier --check . --debug-check
|
|
615
|
+
```
|
|
616
|
+
|
|
544
617
|
## Troubleshooting
|
|
545
618
|
|
|
619
|
+
### Tools Processing Build Outputs
|
|
620
|
+
|
|
621
|
+
If you see errors about linting/formatting files in `dist/`, `coverage/`, or `out/`:
|
|
622
|
+
|
|
623
|
+
1. **ESLint**: Ignore patterns are applied automatically ✅
|
|
624
|
+
2. **Stylelint**: Ignore patterns are applied automatically ✅
|
|
625
|
+
3. **Prettier**: Check that `.prettierignore` was created. If not, re-run config creation or manually create the file.
|
|
626
|
+
|
|
627
|
+
**Solution**: If `.prettierignore` is missing, it will be auto-created next time you use the config. Or create it manually:
|
|
628
|
+
|
|
629
|
+
```bash
|
|
630
|
+
# Let Prettier generate it
|
|
631
|
+
node -e "import('@dimensional-innovations/tool-config').then(m => m.createConfig('prettier'))"
|
|
632
|
+
```
|
|
633
|
+
|
|
546
634
|
### ESLint Not Detecting Framework
|
|
547
635
|
|
|
548
636
|
Ensure your `package.json` includes the framework dependency:
|
package/bin/setup-tool-config.js
CHANGED
|
@@ -128,28 +128,101 @@ function getConfigFilename(tool) {
|
|
|
128
128
|
}
|
|
129
129
|
|
|
130
130
|
/**
|
|
131
|
-
* Get
|
|
131
|
+
* Get file extensions for Stylelint based on framework and CSS type
|
|
132
|
+
* @param {string} framework - Detected framework
|
|
133
|
+
* @param {Object} cssType - CSS type detection results
|
|
134
|
+
* @returns {string[]} Array of file extensions
|
|
132
135
|
*/
|
|
133
|
-
function
|
|
134
|
-
const
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
136
|
+
function getStylelintExtensions(framework, cssType) {
|
|
137
|
+
const extensions = ['css']
|
|
138
|
+
|
|
139
|
+
// Add preprocessor extensions
|
|
140
|
+
if (cssType.preprocessor === 'scss') {
|
|
141
|
+
extensions.push('scss')
|
|
142
|
+
} else if (cssType.preprocessor === 'less') {
|
|
143
|
+
extensions.push('less')
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Add framework-specific extensions
|
|
147
|
+
if (framework === 'vue') extensions.push('vue')
|
|
148
|
+
if (framework === 'svelte') extensions.push('svelte')
|
|
149
|
+
|
|
150
|
+
return extensions
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Generate framework-aware scripts based on detection
|
|
155
|
+
* @param {string} tool - Tool name
|
|
156
|
+
* @param {Object} detected - Detected configuration
|
|
157
|
+
* @returns {Object} Tool-specific scripts
|
|
158
|
+
*/
|
|
159
|
+
function getSmartScripts(tool, detected) {
|
|
160
|
+
switch (tool) {
|
|
161
|
+
case 'stylelint': {
|
|
162
|
+
const extensions = getStylelintExtensions(detected.framework, detected.cssType)
|
|
163
|
+
const pattern =
|
|
164
|
+
extensions.length === 1 ? `**/*.${extensions[0]}` : `**/*.{${extensions.join(',')}}`
|
|
165
|
+
|
|
166
|
+
return {
|
|
167
|
+
style: `stylelint "${pattern}"`,
|
|
168
|
+
'style:fix': `stylelint "${pattern}" --fix`
|
|
169
|
+
}
|
|
149
170
|
}
|
|
171
|
+
|
|
172
|
+
case 'eslint':
|
|
173
|
+
return {
|
|
174
|
+
lint: 'eslint .',
|
|
175
|
+
'lint:fix': 'eslint --fix .'
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
case 'prettier':
|
|
179
|
+
return {
|
|
180
|
+
'prettier:fix': 'prettier --write .',
|
|
181
|
+
prettier: 'prettier --check .'
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
case 'semantic-release':
|
|
185
|
+
return {
|
|
186
|
+
release: 'semantic-release'
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
default:
|
|
190
|
+
return {}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Get npm scripts for a tool
|
|
196
|
+
* @param {string} tool - Tool name
|
|
197
|
+
* @param {Object} [detected] - Optional detected configuration for smart scripts
|
|
198
|
+
* @returns {Object} Tool-specific scripts
|
|
199
|
+
*/
|
|
200
|
+
function getToolScripts(tool, detected = null) {
|
|
201
|
+
// If no detection provided, use basic scripts
|
|
202
|
+
if (!detected) {
|
|
203
|
+
return (
|
|
204
|
+
{
|
|
205
|
+
eslint: {
|
|
206
|
+
lint: 'eslint .',
|
|
207
|
+
'lint:fix': 'eslint --fix .'
|
|
208
|
+
},
|
|
209
|
+
prettier: {
|
|
210
|
+
'prettier:fix': 'prettier --write .',
|
|
211
|
+
prettier: 'prettier --check .'
|
|
212
|
+
},
|
|
213
|
+
stylelint: {
|
|
214
|
+
style: 'stylelint "**/*.css"',
|
|
215
|
+
'style:fix': 'stylelint "**/*.css" --fix'
|
|
216
|
+
},
|
|
217
|
+
'semantic-release': {
|
|
218
|
+
release: 'semantic-release'
|
|
219
|
+
}
|
|
220
|
+
}[tool] || {}
|
|
221
|
+
)
|
|
150
222
|
}
|
|
151
223
|
|
|
152
|
-
|
|
224
|
+
// Generate framework-aware scripts
|
|
225
|
+
return getSmartScripts(tool, detected)
|
|
153
226
|
}
|
|
154
227
|
|
|
155
228
|
/**
|
|
@@ -207,7 +280,7 @@ function writeConfigFile(tool, cwd, dryRun = false) {
|
|
|
207
280
|
/**
|
|
208
281
|
* Update package.json with scripts
|
|
209
282
|
*/
|
|
210
|
-
function updatePackageJsonScripts(tools, cwd, dryRun = false) {
|
|
283
|
+
function updatePackageJsonScripts(tools, detected, cwd, dryRun = false) {
|
|
211
284
|
const packageJsonPath = join(cwd, 'package.json')
|
|
212
285
|
|
|
213
286
|
if (!existsSync(packageJsonPath)) {
|
|
@@ -224,7 +297,7 @@ function updatePackageJsonScripts(tools, cwd, dryRun = false) {
|
|
|
224
297
|
|
|
225
298
|
const scriptsToAdd = {}
|
|
226
299
|
for (const tool of tools) {
|
|
227
|
-
const toolScripts = getToolScripts(tool)
|
|
300
|
+
const toolScripts = getToolScripts(tool, detected)
|
|
228
301
|
for (const [name, command] of Object.entries(toolScripts)) {
|
|
229
302
|
if (!packageJson.scripts[name]) {
|
|
230
303
|
scriptsToAdd[name] = command
|
|
@@ -389,7 +462,7 @@ function copyCITemplate(provider, cwd, dryRun = false) {
|
|
|
389
462
|
/**
|
|
390
463
|
* Setup tools
|
|
391
464
|
*/
|
|
392
|
-
function setupTools(tools, cwd, dryRun = false) {
|
|
465
|
+
function setupTools(tools, detected, cwd, dryRun = false) {
|
|
393
466
|
console.log('')
|
|
394
467
|
console.log('📝 Generating configuration files...')
|
|
395
468
|
console.log('')
|
|
@@ -402,7 +475,7 @@ function setupTools(tools, cwd, dryRun = false) {
|
|
|
402
475
|
console.log('')
|
|
403
476
|
console.log('📦 Updating package.json scripts...')
|
|
404
477
|
console.log('')
|
|
405
|
-
updatePackageJsonScripts(tools, cwd, dryRun)
|
|
478
|
+
updatePackageJsonScripts(tools, detected, cwd, dryRun)
|
|
406
479
|
}
|
|
407
480
|
|
|
408
481
|
/**
|
|
@@ -508,7 +581,7 @@ async function main() {
|
|
|
508
581
|
// Handle --all flag
|
|
509
582
|
if (flags.all) {
|
|
510
583
|
const tools = ['eslint', 'prettier', 'stylelint', 'semantic-release']
|
|
511
|
-
setupTools(tools, cwd, flags.dryRun)
|
|
584
|
+
setupTools(tools, detected, cwd, flags.dryRun)
|
|
512
585
|
console.log('')
|
|
513
586
|
if (flags.dryRun) {
|
|
514
587
|
console.log('ℹ️ Dry run mode - no files were modified')
|
|
@@ -530,7 +603,7 @@ async function main() {
|
|
|
530
603
|
process.exit(1)
|
|
531
604
|
}
|
|
532
605
|
|
|
533
|
-
setupTools([singleTool], cwd, flags.dryRun)
|
|
606
|
+
setupTools([singleTool], detected, cwd, flags.dryRun)
|
|
534
607
|
|
|
535
608
|
// If semantic-release + --ci flag, setup CI
|
|
536
609
|
if (singleTool === 'semantic-release' && hasCI) {
|
|
@@ -604,7 +677,7 @@ async function main() {
|
|
|
604
677
|
process.exit(0)
|
|
605
678
|
}
|
|
606
679
|
|
|
607
|
-
setupTools(response.tools, cwd, flags.dryRun)
|
|
680
|
+
setupTools(response.tools, detected, cwd, flags.dryRun)
|
|
608
681
|
|
|
609
682
|
// If semantic-release selected, prompt for CI setup
|
|
610
683
|
if (response.tools.includes('semantic-release')) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dimensional-innovations/tool-config",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Universal configuration package for ESLint, Prettier, Stylelint, and semantic-release with auto-detection for React, Vue, Svelte, Solid, Astro, Angular, and more",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
@@ -2,6 +2,7 @@ import js from '@eslint/js'
|
|
|
2
2
|
import tseslint from 'typescript-eslint'
|
|
3
3
|
|
|
4
4
|
import { autoDetect } from '../../detectors.js'
|
|
5
|
+
import { getEslintIgnores } from '../../utils/ignore-patterns.js'
|
|
5
6
|
|
|
6
7
|
import basePreset from './presets/base.js'
|
|
7
8
|
import browserEnv from './presets/environments/browser.js'
|
|
@@ -234,13 +235,7 @@ export async function createEslintConfig(options = {}) {
|
|
|
234
235
|
)
|
|
235
236
|
}
|
|
236
237
|
|
|
237
|
-
const defaultIgnorePaths =
|
|
238
|
-
'**/node_modules/**',
|
|
239
|
-
'**/dist/**',
|
|
240
|
-
'**/build/**',
|
|
241
|
-
'**/.next/**',
|
|
242
|
-
'**/.nuxt/**'
|
|
243
|
-
]
|
|
238
|
+
const defaultIgnorePaths = getEslintIgnores()
|
|
244
239
|
const allIgnorePaths = [...defaultIgnorePaths, ...(options.ignorePaths || [])]
|
|
245
240
|
|
|
246
241
|
const config = []
|
|
@@ -37,7 +37,7 @@ export default {
|
|
|
37
37
|
|
|
38
38
|
// Code quality
|
|
39
39
|
eqeqeq: ['error', 'always'], // Always use === and !== instead of == and !=
|
|
40
|
-
'no-duplicate-imports': '
|
|
40
|
+
'no-duplicate-imports': 'off', // Handled by import/no-duplicates (better type + value import support)
|
|
41
41
|
'no-useless-computed-key': 'error', // Disallow unnecessary computed property keys
|
|
42
42
|
'no-useless-constructor': 'error', // Disallow unnecessary constructors
|
|
43
43
|
'no-useless-rename': 'error', // Disallow renaming import/export/destructured assignments to same name
|
|
@@ -47,7 +47,7 @@ export default {
|
|
|
47
47
|
|
|
48
48
|
// Async/Promise best practices
|
|
49
49
|
'no-return-await': 'error', // Disallow unnecessary return await
|
|
50
|
-
'require-await': '
|
|
50
|
+
'require-await': 'warn', // Warn on async functions without await (allow for plugin patterns)
|
|
51
51
|
'no-promise-executor-return': 'error', // Disallow returning values from Promise executor functions
|
|
52
52
|
|
|
53
53
|
// ============================================================
|
|
@@ -1,6 +1,102 @@
|
|
|
1
1
|
import vuePlugin from 'eslint-plugin-vue'
|
|
2
2
|
import tseslint from 'typescript-eslint'
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Vue.js 3 custom rules
|
|
6
|
+
* Vue 3 best practices and conventions
|
|
7
|
+
* Documentation: https://eslint.vuejs.org/rules/
|
|
8
|
+
*/
|
|
9
|
+
const vueCustomRules = {
|
|
10
|
+
// Component naming
|
|
11
|
+
'vue/component-name-in-template-casing': ['error', 'PascalCase'],
|
|
12
|
+
'vue/multi-word-component-names': 'off',
|
|
13
|
+
'vue/component-definition-name-casing': ['error', 'PascalCase'],
|
|
14
|
+
|
|
15
|
+
// Template best practices
|
|
16
|
+
'vue/html-self-closing': [
|
|
17
|
+
'error',
|
|
18
|
+
{
|
|
19
|
+
html: {
|
|
20
|
+
void: 'any',
|
|
21
|
+
normal: 'always',
|
|
22
|
+
component: 'always'
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
],
|
|
26
|
+
'vue/max-attributes-per-line': [
|
|
27
|
+
'error',
|
|
28
|
+
{
|
|
29
|
+
singleline: 3,
|
|
30
|
+
multiline: 1
|
|
31
|
+
}
|
|
32
|
+
],
|
|
33
|
+
'vue/first-attribute-linebreak': [
|
|
34
|
+
'error',
|
|
35
|
+
{
|
|
36
|
+
singleline: 'ignore',
|
|
37
|
+
multiline: 'below'
|
|
38
|
+
}
|
|
39
|
+
],
|
|
40
|
+
'vue/html-closing-bracket-newline': [
|
|
41
|
+
'error',
|
|
42
|
+
{
|
|
43
|
+
singleline: 'never',
|
|
44
|
+
multiline: 'always'
|
|
45
|
+
}
|
|
46
|
+
],
|
|
47
|
+
|
|
48
|
+
// Vue 3 Composition API
|
|
49
|
+
'vue/no-deprecated-v-on-native-modifier': 'error',
|
|
50
|
+
'vue/no-deprecated-slot-attribute': 'error',
|
|
51
|
+
'vue/require-explicit-emits': 'error',
|
|
52
|
+
'vue/no-setup-props-reactivity-loss': 'error',
|
|
53
|
+
'vue/component-api-style': ['error', ['script-setup']],
|
|
54
|
+
'vue/define-macros-order': [
|
|
55
|
+
'error',
|
|
56
|
+
{
|
|
57
|
+
order: ['defineProps', 'defineEmits']
|
|
58
|
+
}
|
|
59
|
+
],
|
|
60
|
+
'vue/define-emits-declaration': ['error', 'type-based'],
|
|
61
|
+
|
|
62
|
+
// Directives
|
|
63
|
+
'vue/no-v-html': 'warn',
|
|
64
|
+
'vue/v-on-event-hyphenation': ['error', 'always'],
|
|
65
|
+
'vue/v-bind-style': ['error', 'shorthand'],
|
|
66
|
+
'vue/v-on-style': ['error', 'shorthand'],
|
|
67
|
+
|
|
68
|
+
// Attributes
|
|
69
|
+
'vue/attribute-hyphenation': ['error', 'always'],
|
|
70
|
+
'vue/prop-name-casing': ['error', 'camelCase'],
|
|
71
|
+
|
|
72
|
+
// Order and organization
|
|
73
|
+
'vue/order-in-components': [
|
|
74
|
+
'error',
|
|
75
|
+
{
|
|
76
|
+
order: [
|
|
77
|
+
'el',
|
|
78
|
+
'name',
|
|
79
|
+
'parent',
|
|
80
|
+
'functional',
|
|
81
|
+
['delimiters', 'comments'],
|
|
82
|
+
['components', 'directives', 'filters'],
|
|
83
|
+
'extends',
|
|
84
|
+
'mixins',
|
|
85
|
+
'inheritAttrs',
|
|
86
|
+
'model',
|
|
87
|
+
['props', 'propsData'],
|
|
88
|
+
'data',
|
|
89
|
+
'computed',
|
|
90
|
+
'watch',
|
|
91
|
+
'LIFECYCLE_HOOKS',
|
|
92
|
+
'methods',
|
|
93
|
+
['template', 'render'],
|
|
94
|
+
'renderError'
|
|
95
|
+
]
|
|
96
|
+
}
|
|
97
|
+
]
|
|
98
|
+
}
|
|
99
|
+
|
|
4
100
|
/**
|
|
5
101
|
* Vue.js 3 configuration
|
|
6
102
|
* Includes Vue plugin and Vue-specific rules
|
|
@@ -13,102 +109,7 @@ export default function createVuePreset() {
|
|
|
13
109
|
// Vue-specific custom rules
|
|
14
110
|
{
|
|
15
111
|
files: ['**/*.vue', '**/*.js', '**/*.ts', '**/*.tsx'],
|
|
16
|
-
rules:
|
|
17
|
-
// ============================================================
|
|
18
|
-
// VUE.JS RULES
|
|
19
|
-
// Vue 3 best practices and conventions
|
|
20
|
-
// Documentation: https://eslint.vuejs.org/rules/
|
|
21
|
-
// ============================================================
|
|
22
|
-
|
|
23
|
-
// Component naming
|
|
24
|
-
'vue/component-name-in-template-casing': ['error', 'PascalCase'], // Use PascalCase for components in templates
|
|
25
|
-
'vue/multi-word-component-names': 'off', // Allow single-word component names (too strict)
|
|
26
|
-
'vue/component-definition-name-casing': ['error', 'PascalCase'], // Use PascalCase for component definitions
|
|
27
|
-
|
|
28
|
-
// Template best practices
|
|
29
|
-
'vue/html-self-closing': [
|
|
30
|
-
'error',
|
|
31
|
-
{
|
|
32
|
-
html: {
|
|
33
|
-
void: 'always',
|
|
34
|
-
normal: 'always',
|
|
35
|
-
component: 'always'
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
], // Always use self-closing tags for consistency
|
|
39
|
-
'vue/max-attributes-per-line': [
|
|
40
|
-
'error',
|
|
41
|
-
{
|
|
42
|
-
singleline: 3,
|
|
43
|
-
multiline: 1
|
|
44
|
-
}
|
|
45
|
-
], // Limit attributes per line for readability
|
|
46
|
-
'vue/first-attribute-linebreak': [
|
|
47
|
-
'error',
|
|
48
|
-
{
|
|
49
|
-
singleline: 'ignore',
|
|
50
|
-
multiline: 'below'
|
|
51
|
-
}
|
|
52
|
-
], // Enforce consistent attribute line breaks
|
|
53
|
-
'vue/html-closing-bracket-newline': [
|
|
54
|
-
'error',
|
|
55
|
-
{
|
|
56
|
-
singleline: 'never',
|
|
57
|
-
multiline: 'always'
|
|
58
|
-
}
|
|
59
|
-
], // Enforce consistent closing bracket placement
|
|
60
|
-
|
|
61
|
-
// Vue 3 Composition API
|
|
62
|
-
'vue/no-deprecated-v-on-native-modifier': 'error', // No .native modifier in Vue 3
|
|
63
|
-
'vue/no-deprecated-slot-attribute': 'error', // Use v-slot instead of slot attribute
|
|
64
|
-
'vue/require-explicit-emits': 'error', // Require emits to be declared
|
|
65
|
-
'vue/no-setup-props-reactivity-loss': 'error', // Don't lose reactivity when using props
|
|
66
|
-
'vue/component-api-style': ['error', ['script-setup']], // Prefer <script setup> syntax
|
|
67
|
-
'vue/define-macros-order': [
|
|
68
|
-
'error',
|
|
69
|
-
{
|
|
70
|
-
order: ['defineProps', 'defineEmits']
|
|
71
|
-
}
|
|
72
|
-
], // Enforce consistent order of compiler macros
|
|
73
|
-
'vue/define-emits-declaration': ['error', 'type-based'], // Use type-based emits declarations
|
|
74
|
-
|
|
75
|
-
// Directives
|
|
76
|
-
'vue/no-v-html': 'warn', // Warn about v-html (XSS risk)
|
|
77
|
-
'vue/v-on-event-hyphenation': ['error', 'always'], // Use kebab-case for event names
|
|
78
|
-
'vue/v-bind-style': ['error', 'shorthand'], // Use : instead of v-bind:
|
|
79
|
-
'vue/v-on-style': ['error', 'shorthand'], // Use @ instead of v-on:
|
|
80
|
-
|
|
81
|
-
// Attributes
|
|
82
|
-
'vue/attribute-hyphenation': ['error', 'always'], // Use kebab-case for attributes in templates
|
|
83
|
-
'vue/prop-name-casing': ['error', 'camelCase'], // Use camelCase for props in script
|
|
84
|
-
|
|
85
|
-
// Order and organization
|
|
86
|
-
'vue/order-in-components': [
|
|
87
|
-
'error',
|
|
88
|
-
{
|
|
89
|
-
order: [
|
|
90
|
-
'el',
|
|
91
|
-
'name',
|
|
92
|
-
'parent',
|
|
93
|
-
'functional',
|
|
94
|
-
['delimiters', 'comments'],
|
|
95
|
-
['components', 'directives', 'filters'],
|
|
96
|
-
'extends',
|
|
97
|
-
'mixins',
|
|
98
|
-
'inheritAttrs',
|
|
99
|
-
'model',
|
|
100
|
-
['props', 'propsData'],
|
|
101
|
-
'data',
|
|
102
|
-
'computed',
|
|
103
|
-
'watch',
|
|
104
|
-
'LIFECYCLE_HOOKS',
|
|
105
|
-
'methods',
|
|
106
|
-
['template', 'render'],
|
|
107
|
-
'renderError'
|
|
108
|
-
]
|
|
109
|
-
}
|
|
110
|
-
] // Enforce consistent component option order
|
|
111
|
-
}
|
|
112
|
+
rules: vueCustomRules
|
|
112
113
|
},
|
|
113
114
|
|
|
114
115
|
// Vue-specific parser configuration
|
|
@@ -120,6 +121,14 @@ export default function createVuePreset() {
|
|
|
120
121
|
extraFileExtensions: ['.vue']
|
|
121
122
|
}
|
|
122
123
|
}
|
|
124
|
+
},
|
|
125
|
+
|
|
126
|
+
// Disable TypeScript naming convention for Vue files (allows onUpdate:modelValue pattern)
|
|
127
|
+
{
|
|
128
|
+
files: ['**/*.vue'],
|
|
129
|
+
rules: {
|
|
130
|
+
'@typescript-eslint/naming-convention': 'off'
|
|
131
|
+
}
|
|
123
132
|
}
|
|
124
133
|
]
|
|
125
134
|
}
|
|
@@ -27,7 +27,13 @@ export default {
|
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
29
|
], // Enforce consistent import order with alphabetization
|
|
30
|
-
'import/no-duplicates':
|
|
30
|
+
'import/no-duplicates': [
|
|
31
|
+
'error',
|
|
32
|
+
{
|
|
33
|
+
'prefer-inline': true,
|
|
34
|
+
considerQueryString: false
|
|
35
|
+
}
|
|
36
|
+
], // Prevent duplicate imports (allows type + value imports from same module)
|
|
31
37
|
'import/no-unresolved': 'off', // TypeScript handles this better
|
|
32
38
|
'import/named': 'off', // TypeScript handles this better
|
|
33
39
|
'import/namespace': 'off', // TypeScript handles this better
|
|
@@ -101,17 +101,28 @@ export default {
|
|
|
101
101
|
selector: 'enumMember',
|
|
102
102
|
format: ['PascalCase', 'UPPER_CASE']
|
|
103
103
|
},
|
|
104
|
-
// Object properties: allow camelCase or
|
|
104
|
+
// Object properties: allow camelCase, PascalCase, or UPPER_CASE (for API responses, component props, env vars)
|
|
105
105
|
{
|
|
106
106
|
selector: 'property',
|
|
107
|
-
format: ['camelCase', 'PascalCase'],
|
|
107
|
+
format: ['camelCase', 'PascalCase', 'UPPER_CASE'],
|
|
108
108
|
leadingUnderscore: 'allow',
|
|
109
109
|
filter: {
|
|
110
|
-
// Allow properties with special characters (ESLint rule names,
|
|
111
|
-
regex: '^(@|no-|prefer-|max-|vue/|import/|spaced-|react
|
|
110
|
+
// Allow properties with special characters (ESLint rule names, path aliases, env vars)
|
|
111
|
+
regex: '^(@|no-|prefer-|max-|vue/|import/|spaced-|react/|[A-Z_]+).*$',
|
|
112
112
|
match: false
|
|
113
113
|
}
|
|
114
114
|
},
|
|
115
|
+
// Object literal properties: allow any format (path aliases like @renderer, @main, @preload)
|
|
116
|
+
{
|
|
117
|
+
selector: 'objectLiteralProperty',
|
|
118
|
+
format: null
|
|
119
|
+
},
|
|
120
|
+
// Imports: allow camelCase or PascalCase (Vue component imports)
|
|
121
|
+
{
|
|
122
|
+
selector: 'import',
|
|
123
|
+
format: ['camelCase', 'PascalCase'],
|
|
124
|
+
leadingUnderscore: 'allow'
|
|
125
|
+
},
|
|
115
126
|
// Private class members: require underscore prefix
|
|
116
127
|
{
|
|
117
128
|
selector: 'memberLike',
|
|
@@ -4,7 +4,11 @@
|
|
|
4
4
|
* Creates Prettier configurations with framework-aware defaults and auto-detection.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
import { existsSync, writeFileSync } from 'fs'
|
|
8
|
+
import { join } from 'path'
|
|
9
|
+
|
|
7
10
|
import { autoDetect } from '../../detectors.js'
|
|
11
|
+
import { getPrettierIgnoreContent } from '../../utils/ignore-patterns.js'
|
|
8
12
|
|
|
9
13
|
import basePreset from './presets/base.js'
|
|
10
14
|
import astroPreset from './presets/frameworks/astro.js'
|
|
@@ -45,6 +49,20 @@ export function createPrettierConfig(options = {}) {
|
|
|
45
49
|
// Auto-detect framework if needed
|
|
46
50
|
const framework = explicitFramework === 'auto' ? autoDetect(cwd).framework : explicitFramework
|
|
47
51
|
|
|
52
|
+
// Auto-generate .prettierignore if it doesn't exist
|
|
53
|
+
const ignoreFile = join(cwd, '.prettierignore')
|
|
54
|
+
if (!existsSync(ignoreFile)) {
|
|
55
|
+
try {
|
|
56
|
+
writeFileSync(ignoreFile, getPrettierIgnoreContent(), 'utf8')
|
|
57
|
+
console.warn('📝 Prettier: Created .prettierignore file')
|
|
58
|
+
} catch {
|
|
59
|
+
console.warn(
|
|
60
|
+
'⚠️ Prettier: Could not create .prettierignore file automatically.\n' +
|
|
61
|
+
' Please create it manually or ensure write permissions.'
|
|
62
|
+
)
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
48
66
|
// Start with base configuration
|
|
49
67
|
const config = { ...basePreset }
|
|
50
68
|
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import { autoDetect, detectCssType } from '../../detectors.js'
|
|
11
|
+
import { getStylelintIgnores } from '../../utils/ignore-patterns.js'
|
|
11
12
|
|
|
12
13
|
import basePreset from './presets/base.js'
|
|
13
14
|
import cssModulesPreset from './presets/css-modules.js'
|
|
@@ -127,6 +128,9 @@ export function createStylelintConfig(options = {}) {
|
|
|
127
128
|
? { ...scssPreset, customSyntax: 'postcss-scss' }
|
|
128
129
|
: { ...basePreset }
|
|
129
130
|
|
|
131
|
+
// Add default ignore patterns
|
|
132
|
+
config.ignoreFiles = getStylelintIgnores()
|
|
133
|
+
|
|
130
134
|
// Apply Tailwind preset if detected
|
|
131
135
|
if (cssType?.tailwind) {
|
|
132
136
|
mergePreset(config, tailwindPreset)
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared ignore patterns for all tools
|
|
3
|
+
*
|
|
4
|
+
* Provides consistent ignore patterns across ESLint, Prettier, and Stylelint
|
|
5
|
+
* to prevent processing build outputs, dependencies, and generated files.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Common directories that should be ignored by all tools
|
|
10
|
+
*/
|
|
11
|
+
export const COMMON_IGNORE_DIRS = [
|
|
12
|
+
'node_modules',
|
|
13
|
+
'dist',
|
|
14
|
+
'build',
|
|
15
|
+
'out',
|
|
16
|
+
'coverage',
|
|
17
|
+
'.nyc_output'
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Framework-specific build outputs
|
|
22
|
+
*/
|
|
23
|
+
export const FRAMEWORK_BUILD_DIRS = [
|
|
24
|
+
'.next', // Next.js
|
|
25
|
+
'.nuxt', // Nuxt
|
|
26
|
+
'.output', // Nitro/Nuxt3
|
|
27
|
+
'.vercel', // Vercel
|
|
28
|
+
'.netlify', // Netlify
|
|
29
|
+
'.cache', // Gatsby/Parcel
|
|
30
|
+
'.parcel-cache', // Parcel
|
|
31
|
+
'.turbo', // Turborepo
|
|
32
|
+
'.vite', // Vite
|
|
33
|
+
'.svelte-kit' // SvelteKit
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Lock files and generated files
|
|
38
|
+
*/
|
|
39
|
+
export const GENERATED_FILES = [
|
|
40
|
+
'package-lock.json',
|
|
41
|
+
'pnpm-lock.yaml',
|
|
42
|
+
'yarn.lock',
|
|
43
|
+
'bun.lockb',
|
|
44
|
+
'CHANGELOG.md'
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Minified files
|
|
49
|
+
*/
|
|
50
|
+
export const MINIFIED_FILES = ['*.min.js', '*.min.css', '*.min.mjs']
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Get ESLint ignore patterns (flat config format)
|
|
54
|
+
* @returns {string[]} Array of glob patterns for ESLint ignores array
|
|
55
|
+
*/
|
|
56
|
+
export function getEslintIgnores() {
|
|
57
|
+
return [
|
|
58
|
+
...COMMON_IGNORE_DIRS.map(dir => `**/${dir}/**`),
|
|
59
|
+
...FRAMEWORK_BUILD_DIRS.map(dir => `**/${dir}/**`),
|
|
60
|
+
...MINIFIED_FILES.map(pattern => `**/${pattern}`)
|
|
61
|
+
]
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Get Stylelint ignore patterns (ignoreFiles format)
|
|
66
|
+
* @returns {string[]} Array of glob patterns for Stylelint ignoreFiles
|
|
67
|
+
*/
|
|
68
|
+
export function getStylelintIgnores() {
|
|
69
|
+
return [
|
|
70
|
+
...COMMON_IGNORE_DIRS.map(dir => `**/${dir}/**`),
|
|
71
|
+
...FRAMEWORK_BUILD_DIRS.map(dir => `**/${dir}/**`),
|
|
72
|
+
...MINIFIED_FILES.map(pattern => `**/${pattern}`)
|
|
73
|
+
]
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Get Prettier ignore content (.prettierignore file format)
|
|
78
|
+
* @returns {string} .prettierignore file content
|
|
79
|
+
*/
|
|
80
|
+
export function getPrettierIgnoreContent() {
|
|
81
|
+
return `# Dependencies
|
|
82
|
+
node_modules/
|
|
83
|
+
.pnp/
|
|
84
|
+
.pnp.js
|
|
85
|
+
|
|
86
|
+
# Build outputs
|
|
87
|
+
${COMMON_IGNORE_DIRS.filter(dir => dir !== 'node_modules' && dir !== 'coverage')
|
|
88
|
+
.map(dir => `${dir}/`)
|
|
89
|
+
.join('\n')}
|
|
90
|
+
${FRAMEWORK_BUILD_DIRS.map(dir => `${dir}/`).join('\n')}
|
|
91
|
+
|
|
92
|
+
# Coverage
|
|
93
|
+
coverage/
|
|
94
|
+
.nyc_output/
|
|
95
|
+
*.lcov
|
|
96
|
+
|
|
97
|
+
# Lock files
|
|
98
|
+
${GENERATED_FILES.filter(f => f.includes('lock') || f.includes('.lock')).join('\n')}
|
|
99
|
+
|
|
100
|
+
# Generated files
|
|
101
|
+
CHANGELOG.md
|
|
102
|
+
|
|
103
|
+
# Cache directories
|
|
104
|
+
.cache/
|
|
105
|
+
.parcel-cache/
|
|
106
|
+
.turbo/
|
|
107
|
+
.vite/
|
|
108
|
+
|
|
109
|
+
# Environment files (may contain secrets)
|
|
110
|
+
.env
|
|
111
|
+
.env.local
|
|
112
|
+
.env.*.local
|
|
113
|
+
|
|
114
|
+
# IDE
|
|
115
|
+
.vscode/
|
|
116
|
+
.idea/
|
|
117
|
+
|
|
118
|
+
# OS files
|
|
119
|
+
.DS_Store
|
|
120
|
+
Thumbs.db
|
|
121
|
+
`
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Get Stylelint ignore content (.stylelintignore file format)
|
|
126
|
+
* @returns {string} .stylelintignore file content
|
|
127
|
+
*/
|
|
128
|
+
export function getStylelintIgnoreContent() {
|
|
129
|
+
return `# Dependencies
|
|
130
|
+
node_modules/
|
|
131
|
+
|
|
132
|
+
# Build outputs
|
|
133
|
+
${COMMON_IGNORE_DIRS.filter(dir => dir !== 'node_modules' && dir !== 'coverage')
|
|
134
|
+
.map(dir => `${dir}/`)
|
|
135
|
+
.join('\n')}
|
|
136
|
+
${FRAMEWORK_BUILD_DIRS.map(dir => `${dir}/`).join('\n')}
|
|
137
|
+
|
|
138
|
+
# Coverage
|
|
139
|
+
coverage/
|
|
140
|
+
.nyc_output/
|
|
141
|
+
|
|
142
|
+
# Minified files
|
|
143
|
+
${MINIFIED_FILES.join('\n')}
|
|
144
|
+
`
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export default {
|
|
148
|
+
COMMON_IGNORE_DIRS,
|
|
149
|
+
FRAMEWORK_BUILD_DIRS,
|
|
150
|
+
GENERATED_FILES,
|
|
151
|
+
MINIFIED_FILES,
|
|
152
|
+
getEslintIgnores,
|
|
153
|
+
getStylelintIgnores,
|
|
154
|
+
getPrettierIgnoreContent,
|
|
155
|
+
getStylelintIgnoreContent
|
|
156
|
+
}
|