@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 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:
@@ -128,28 +128,101 @@ function getConfigFilename(tool) {
128
128
  }
129
129
 
130
130
  /**
131
- * Get npm scripts for a tool
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 getToolScripts(tool) {
134
- const scripts = {
135
- eslint: {
136
- lint: 'eslint .',
137
- 'lint:fix': 'eslint --fix .'
138
- },
139
- prettier: {
140
- 'prettier:fix': 'prettier --write .',
141
- prettier: 'prettier --check .'
142
- },
143
- stylelint: {
144
- style: 'stylelint "**/*.css"',
145
- 'style:fix': 'stylelint "**/*.css" --fix'
146
- },
147
- 'semantic-release': {
148
- release: 'semantic-release'
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
- return scripts[tool] || {}
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.0.0",
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': 'error', // Prevent duplicate imports from same module
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': 'error', // Disallow async functions that don't use 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': 'error', // Prevent duplicate imports from same module
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 PascalCase (for API responses, component props)
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, etc.)
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
+ }