@mikey-pro/eslint-config-vue 8.1.0 → 9.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (5) hide show
  1. package/README.md +18 -3
  2. package/flat.js +3 -0
  3. package/index.js +147 -273
  4. package/legacy.js +64 -0
  5. package/package.json +36 -15
package/README.md CHANGED
@@ -18,14 +18,29 @@ A preset ESLint Vue configuration
18
18
  npm i -D mikey-pro @mikey-pro/eslint-config-vue
19
19
  ```
20
20
 
21
- ### Configure
21
+ ### Configure (Flat ESLint v9+ Default)
22
22
 
23
- Extend to ESLint in `package.json`:
23
+ ```js
24
+ // eslint.config.js
25
+ import vueConfig from '@mikey-pro/eslint-config-vue';
26
+
27
+ export default vueConfig;
28
+ ```
29
+
30
+ ### Legacy (eslintrc) Configuration (still supported)
31
+
32
+ Legacy consumers should explicitly import the legacy entry:
24
33
 
25
34
  ```json
26
35
  {
27
36
  "eslintConfig": {
28
- "extends": ["@mikey-pro/eslint-config-vue"]
37
+ "extends": ["@mikey-pro/eslint-config-vue/legacy"]
29
38
  }
30
39
  }
31
40
  ```
41
+
42
+ Or via direct require:
43
+
44
+ ```js
45
+ module.exports = require('@mikey-pro/eslint-config-vue/legacy');
46
+ ```
package/flat.js ADDED
@@ -0,0 +1,3 @@
1
+ // Modern Vue ESLint 9 Flat Configuration for Mikey Pro
2
+
3
+ export { default } from './index.js';
package/index.js CHANGED
@@ -1,282 +1,156 @@
1
- import baseConfig from '@mikey-pro/eslint-config';
2
- import vuePlugin from 'eslint-plugin-vue';
3
- import vueRecommended from 'eslint-plugin-vue/lib/configs/vue3-recommended.js';
4
-
5
- const vueConfig = [
6
- ...baseConfig,
7
- {
8
- files: ['*.vue'],
9
- languageOptions: {
10
- parser: 'vue-eslint-parser',
11
- parserOptions: {
12
- parser: {
13
- js: '@babel/eslint-parser',
14
- ts: '@typescript-eslint/parser',
15
- '<template>': 'espree'
16
- },
17
- babelOptions: {
18
- plugins: [
19
- [
20
- '@babel/plugin-transform-react-jsx',
21
- {
22
- pragma: 'h',
23
- pragmaFrag: 'Fragment',
24
- runtime: 'automatic',
25
- },
26
- ],
27
- ],
28
- presets: [
29
- [
30
- '@babel/preset-env',
31
- {
32
- targets: {
33
- node: 'current',
34
- },
35
- },
36
- ],
37
- ],
38
- },
39
- ecmaVersion: 'latest',
40
- requireConfigFile: false,
41
- sourceType: 'module',
42
- extraFileExtensions: ['.vue'],
43
- vueFeatures: {
44
- filter: true,
45
- interpolationAsNonHTML: false,
46
- styleCSSVariableInjection: true
47
- }
1
+ // Modern Vue ESLint configuration for Mikey Pro
2
+ import { baseConfig } from '@mikey-pro/eslint-config/base-config.js';
3
+ import { baseOverrides } from '@mikey-pro/eslint-config/overrides.js';
4
+ import vue from 'eslint-plugin-vue';
5
+ import vueParser from 'vue-eslint-parser';
6
+
7
+ // Vue-specific configuration
8
+ const vueConfig = {
9
+ files: ['**/*.vue'],
10
+ languageOptions: {
11
+ parser: vueParser,
12
+ parserOptions: {
13
+ ecmaFeatures: {
14
+ jsx: true,
48
15
  },
16
+ ecmaVersion: 'latest',
17
+ sourceType: 'module',
49
18
  },
50
- plugins: {
51
- vue: vuePlugin,
52
- },
53
- rules: {
54
- ...vueRecommended.rules,
55
-
56
- // Vue 3 Composition API
57
- 'vue/component-api-style': ['error', ['script-setup', 'composition']],
58
- 'vue/no-ref-object-destructure': 'error',
59
- 'vue/no-setup-props-destructure': 'error',
60
-
61
- // Best Practices
62
- 'vue/no-useless-v-bind': 'error',
63
- 'vue/prefer-separate-static-class': 'error',
64
-
65
- // Performance
66
- 'vue/no-async-in-computed-properties': 'error',
67
- 'vue/no-static-inline-styles': 'warn',
68
-
69
- // Type Safety
70
- 'vue/component-definition-name-casing': ['error', 'PascalCase'],
71
- 'vue/match-component-file-name': ['error', {
72
- extensions: ['vue'],
73
- shouldMatchCase: true
74
- }],
75
- 'vue/component-options-name-casing': ['error', 'PascalCase'],
76
-
77
- // Best Practices
78
- 'vue/no-required-prop-with-default': 'error',
79
- 'vue/require-typed-ref': 'error',
80
- 'vue/valid-define-props': 'error',
81
-
82
- // Existing rules...
83
- 'vue/component-tags-order': [
84
- 'warn',
85
- {
86
- order: [['script', 'template'], 'style'],
87
- },
88
- ],
89
- 'vue/html-self-closing': [
90
- 'warn',
91
- {
92
- html: {
93
- component: 'always',
94
- normal: 'always',
95
- void: 'always',
96
- },
97
- math: 'always',
98
- svg: 'always',
19
+ },
20
+ plugins: {
21
+ vue,
22
+ },
23
+ rules: {
24
+ // Vue rules
25
+ ...vue.configs['vue3-recommended'].rules,
26
+
27
+ // Basic Vue-specific overrides
28
+ 'vue/attribute-hyphenation': ['error', 'always'],
29
+ 'vue/component-definition-name-casing': ['error', 'PascalCase'],
30
+ 'vue/component-name-in-template-casing': ['error', 'PascalCase'],
31
+ 'vue/custom-event-name-casing': ['error', 'camelCase'],
32
+ 'vue/define-emits-declaration': ['error', 'type-based'],
33
+ 'vue/define-props-declaration': ['error', 'type-based'],
34
+ 'vue/html-button-has-type': 'error',
35
+ 'vue/html-indent': ['error', 2],
36
+ 'vue/html-self-closing': [
37
+ 'error',
38
+ {
39
+ html: {
40
+ component: 'always',
41
+ normal: 'always',
42
+ void: 'always',
99
43
  },
100
- ],
101
- 'vue/singleline-html-element-content-newline': 'off',
102
- 'prettier/prettier': ['warn', { parser: 'vue' }],
103
-
104
- // Enhanced Type Safety
105
- 'vue/no-export-in-script-setup': 'error',
106
-
107
- // Script Setup
108
- 'vue/no-undef-components': ['error', {
109
- ignorePatterns: ['router-view', 'router-link'],
110
- }],
111
-
112
- // Composables
113
- 'vue/custom-event-name-casing': ['error', 'camelCase', {
114
- ignore: []
115
- }],
116
-
117
- // Security
118
- 'vue/no-unescaped-html': 'error',
119
- 'vue/no-potential-component-option-typo': 'error',
120
- 'vue/no-restricted-component-options': ['error', {
121
- name: 'data',
122
- message: 'Use setup() instead'
123
- }],
124
- 'vue/no-restricted-v-bind': ['error', '/^v-/'],
125
- 'vue/no-restricted-html-elements': [
126
- 'error',
127
- 'iframe',
128
- 'object',
129
- 'embed'
130
- ],
131
- 'vue/no-use-v-if-with-v-for': ['error', {
132
- allowUsingIterationVar: false
133
- }],
134
-
135
- // Optimization
136
- 'vue/no-unused-properties': ['error', {
137
- groups: ['props', 'data', 'computed', 'methods', 'setup'],
138
- deepData: true
139
- }],
140
- 'vue/no-unused-refs': 'error',
141
- 'vue/valid-next-tick': 'error',
142
-
143
- // Performance
144
- 'vue/no-parsing-error': ['error', {
145
- 'invalid-first-character-of-tag-name': false
146
- }],
147
- 'vue/no-unused-components': ['error', {
148
- ignoreWhenBindingPresent: true
149
- }],
150
- 'vue/valid-v-slot': ['error', {
151
- allowModifiers: true
152
- }],
153
-
154
- // Advanced Vue 3 Features
155
- 'vue/prefer-true-attribute-shorthand': ['error', 'always'],
156
- 'vue/v-on-function-call': ['error', 'never'],
157
- 'vue/no-empty-component-block': 'error',
158
- 'vue/multi-word-component-names': ['error', {
159
- ignores: ['index', 'default']
160
- }],
161
-
162
- // Performance Optimizations
163
- 'vue/no-deprecated-filter': 'error',
164
- 'vue/prefer-template': 'error',
165
- 'vue/no-useless-mustaches': 'error',
166
- 'vue/no-empty-pattern': 'error',
167
-
168
- // Type Safety
169
- 'vue/block-tag-newline': ['error', {
170
- singleline: 'always',
171
- multiline: 'always',
172
- maxEmptyLines: 1
173
- }],
174
-
175
- // Enhanced Performance
176
- 'vue/no-child-content': ['error', {
177
- 'ignoreSlots': ['default']
178
- }],
179
-
180
- // Better Type Safety
181
- 'vue/define-props-declaration': ['error', {
182
- 'type-based': true,
183
- 'required': true
184
- }],
185
- 'vue/define-emits-declaration': ['error', {
186
- 'type-based': true
187
- }],
188
-
189
- // Component Organization
190
- 'vue/block-order': ['error', {
191
- 'order': [
192
- 'script:not([setup])',
193
- 'script[setup]',
194
- 'template',
195
- 'style:not([scoped])',
196
- 'style[scoped]'
197
- ]
198
- }],
199
-
200
- // Vue 3.4+ Features
201
- 'vue/next-tick-style': ['error', 'promise'],
202
- 'vue/require-typed-object-prop': 'error',
203
- 'vue/no-deprecated-model-definition': ['error', {
204
- allowVue3Compat: false
205
- }],
206
-
207
- // Memory Optimization
208
- 'vue/no-ref-as-operand': 'error',
209
- 'vue/prefer-import-from-vue': ['error', {
210
- disallowVuePath: true
211
- }],
212
- 'vue/no-side-effects-in-computed-properties': ['error', {
213
- enforceForEventHandlers: true
214
- }],
215
-
216
- // Strict Mode Features
217
- 'vue/component-name-in-template-casing': ['error', 'PascalCase', {
218
- registeredComponentsOnly: true,
219
- ignores: []
220
- }],
221
- 'vue/define-macros-order': ['error', {
222
- order: [
223
- 'defineOptions',
224
- 'defineSlots',
225
- 'defineEmits',
226
- 'defineModel',
227
- 'defineProps'
228
- ]
229
- }],
44
+ math: 'always',
45
+ svg: 'always',
46
+ },
47
+ ],
48
+ 'vue/max-attributes-per-line': [
49
+ 'error',
50
+ {
51
+ multiline: { max: 1 },
52
+ singleline: { max: 1 },
53
+ },
54
+ ],
55
+ 'vue/multi-word-component-names': 'error',
56
+ 'vue/mustache-interpolation-spacing': ['error', 'always'],
57
+ 'vue/no-multiple-template-root': 'off', // Vue 3 allows multiple roots
58
+ 'vue/no-mutating-props': 'error',
59
+ 'vue/no-unused-components': 'error',
60
+ 'vue/no-unused-vars': 'error',
61
+ 'vue/no-use-v-if-with-v-for': 'error',
62
+ 'vue/no-v-html': 'error',
63
+ 'vue/no-v-model-argument': 'off', // Vue 3 supports v-model arguments
64
+ 'vue/object-curly-spacing': ['error', 'always'],
65
+ 'vue/require-component-is': 'error',
66
+ 'vue/require-default-prop': 'error',
67
+ 'vue/require-prop-types': 'error',
68
+ 'vue/require-v-for-key': 'error',
69
+ 'vue/script-indent': ['error', 2, { baseIndent: 0 }],
70
+ 'vue/this-in-template': 'error',
71
+ 'vue/use-v-on-exact': 'error',
72
+ 'vue/v-for-delimiter-style': ['error', 'in'],
73
+ 'vue/v-on-function-call': 'error',
74
+ 'vue/valid-define-emits': 'error',
75
+ 'vue/valid-define-props': 'error',
76
+ 'vue/valid-next-tick': 'error',
77
+ 'vue/valid-template-root': 'off', // Vue 3 allows multiple roots
78
+ 'vue/valid-v-bind-sync': 'error',
79
+ 'vue/valid-v-cloak': 'error',
80
+ 'vue/valid-v-else': 'error',
81
+ 'vue/valid-v-else-if': 'error',
82
+ 'vue/valid-v-for': 'error',
83
+ 'vue/valid-v-html': 'error',
84
+ 'vue/valid-v-if': 'error',
85
+ 'vue/valid-v-is': 'error',
86
+ 'vue/valid-v-model': 'error',
87
+ 'vue/valid-v-on': 'error',
88
+ 'vue/valid-v-once': 'error',
89
+ 'vue/valid-v-pre': 'error',
90
+ 'vue/valid-v-show': 'error',
91
+ 'vue/valid-v-slot': 'error',
92
+ 'vue/valid-v-text': 'error',
93
+ },
94
+ settings: {
95
+ 'import/resolver': {
96
+ typescript: {
97
+ alwaysTryTypes: true,
98
+ },
99
+ },
100
+ },
101
+ };
230
102
 
231
- // Performance Optimizations
232
- 'vue/no-static-style': 'error',
233
- 'vue/no-undef-properties': ['error', {
234
- ignores: ['/^\$/']
235
- }],
103
+ // Export the complete Vue configuration
104
+ export default [
105
+ // Global ignores
106
+ {
107
+ ignores: [
108
+ '**/dist/**/*',
109
+ '**/vendor/**/*',
110
+ '**/node_modules/**/*',
111
+ '**/coverage/**/*',
112
+ '**/.next/**/*',
113
+ '**/.nuxt/**/*',
114
+ '**/.output/**/*',
115
+ '**/.vite/**/*',
116
+ '**/build/**/*',
117
+ '**/out/**/*',
118
+ '*.properties',
119
+ '*.cclibs',
120
+ '*.svg',
121
+ '*.png',
122
+ '*.jpg',
123
+ '*.jpeg',
124
+ '*.gif',
125
+ '*.ico',
126
+ '*.webp',
127
+ '*.aco',
128
+ '*.psd',
129
+ '*.ai',
130
+ '*.ase',
131
+ '*.sh',
132
+ '*.bat',
133
+ '*.cmd',
134
+ 'package-lock.json',
135
+ 'yarn.lock',
136
+ 'pnpm-lock.yaml',
137
+ 'LICENSE',
138
+ 'CNAME',
139
+ '*.min.js',
140
+ '*.min.css',
141
+ ],
142
+ },
236
143
 
237
- // Script Setup Safety
238
- 'vue/script-setup-uses-vars': ['error', {
239
- checkTemplate: true
240
- }],
241
- 'vue/valid-define-options': ['error', {
242
- presetName: 'script-setup'
243
- }],
144
+ // Base configuration
145
+ baseConfig,
244
146
 
245
- // Performance Optimizations
246
- 'vue/prefer-define-options': ['error', {
247
- presets: ['composition-api', 'script-setup']
248
- }],
249
- 'vue/no-duplicate-attr-inheritance': ['error', {
250
- ignoreKeys: ['class', 'style', 'key', 'ref']
251
- }],
147
+ // Vue-specific configuration
148
+ vueConfig,
252
149
 
253
- // Type Safety
254
- 'vue/no-setup-props-reactivity-loss': 'error',
255
- 'vue/no-watch-after-await': 'error',
256
- 'vue/prefer-prop-type-inference': ['error', {
257
- allowAny: false
258
- }]
259
- },
260
- settings: {
261
- ...baseConfig.settings,
262
- 'import/resolver': {
263
- typescript: {
264
- alwaysTryTypes: true,
265
- project: ['./tsconfig.json', './tsconfig.*.json']
266
- }
267
- },
268
- 'import/core-modules': ['vue', '@vue/composition-api', '@vue/runtime-core', '@vue/runtime-dom'],
269
- 'import/parsers': {
270
- '@typescript-eslint/parser': ['.ts', '.tsx', '.vue', '.d.ts'],
271
- },
272
- 'vue': {
273
- version: '3.4'
274
- }
275
- }
276
- },
150
+ // File-specific overrides
151
+ ...baseOverrides,
277
152
  ];
278
153
 
279
- export default vueConfig;
280
- if (typeof module !== 'undefined' && module.exports) {
281
- module.exports = vueConfig;
282
- }
154
+ // Export individual components for advanced usage
155
+ export { baseConfig } from '@mikey-pro/eslint-config/base-config.js';
156
+ export { baseOverrides } from '@mikey-pro/eslint-config/overrides.js';
package/legacy.js ADDED
@@ -0,0 +1,64 @@
1
+ // Legacy (eslintrc-style) config preserved under /legacy entry point.
2
+ const baseConfig = require('@mikey-pro/eslint-config');
3
+
4
+ module.exports = {
5
+ ...baseConfig,
6
+ overrides: [
7
+ ...baseConfig.overrides,
8
+ {
9
+ extends: ['plugin:vue/vue3-recommended'],
10
+ files: ['*.vue'],
11
+ parser: 'vue-eslint-parser',
12
+ parserOptions: {
13
+ babelOptions: {
14
+ plugins: [
15
+ 'eslint-plugin-vue',
16
+ [
17
+ '@babel/plugin-transform-react-jsx',
18
+ {
19
+ pragma: 'h',
20
+ pragmaFrag: 'Fragment',
21
+ runtime: 'automatic',
22
+ },
23
+ ],
24
+ ],
25
+ presets: [
26
+ [
27
+ '@babel/preset-env',
28
+ {
29
+ targets: {
30
+ node: 'current',
31
+ },
32
+ },
33
+ ],
34
+ ],
35
+ },
36
+ ecmaVersion: 'latest',
37
+ requireConfigFile: false,
38
+ sourceType: 'module',
39
+ },
40
+ rules: {
41
+ 'vue/component-tags-order': [
42
+ 'warn',
43
+ {
44
+ order: [['script', 'template'], 'style'],
45
+ },
46
+ ],
47
+ 'vue/html-self-closing': [
48
+ 'warn',
49
+ {
50
+ html: {
51
+ component: 'always',
52
+ normal: 'always',
53
+ void: 'always',
54
+ },
55
+ math: 'always',
56
+ svg: 'always',
57
+ },
58
+ ],
59
+ 'vue/singleline-html-element-content-newline': 'off',
60
+ 'prettier/prettier': ['warn', { parser: 'vue' }],
61
+ },
62
+ },
63
+ ],
64
+ };
package/package.json CHANGED
@@ -1,21 +1,21 @@
1
1
  {
2
2
  "name": "@mikey-pro/eslint-config-vue",
3
- "version": "8.1.0",
4
- "description": "Mikey Pro ESLint Vue configuration",
3
+ "version": "9.0.1",
4
+ "description": "Mikey Pro ESLint Vue configuration - Ultimate Vue coding style guide",
5
5
  "type": "module",
6
6
  "main": "index.js",
7
7
  "dependencies": {
8
- "@babel/core": "^7.26.8",
9
- "@babel/eslint-parser": "^7.26.8",
10
- "@babel/plugin-transform-react-jsx": "^7.25.9",
11
- "@babel/preset-env": "^7.26.8",
12
- "@mikey-pro/eslint-config": "^8.0.19",
13
- "@typescript-eslint/parser": "^8.24.0",
14
- "eslint-plugin-vue": "^9.32.0",
15
- "vue-eslint-parser": "^9.4.3"
8
+ "@babel/core": "^7.28.4",
9
+ "@babel/eslint-parser": "^7.28.4",
10
+ "@babel/plugin-transform-react-jsx": "^7.28.0",
11
+ "@babel/preset-env": "^7.28.3",
12
+ "@mikey-pro/eslint-config": "^9.0.0",
13
+ "@typescript-eslint/parser": "^8.43.0",
14
+ "eslint-plugin-vue": "^10.4.0",
15
+ "vue-eslint-parser": "^10.2.0"
16
16
  },
17
17
  "peerDependencies": {
18
- "@mikey-pro/eslint-config": "^8.0.3"
18
+ "@mikey-pro/eslint-config": "^9.0.0"
19
19
  },
20
20
  "peerDependenciesMeta": {
21
21
  "@types/node": {
@@ -27,6 +27,8 @@
27
27
  },
28
28
  "files": [
29
29
  "index.js",
30
+ "flat.js",
31
+ "legacy.js",
30
32
  "README.md",
31
33
  "LICENSE"
32
34
  ],
@@ -40,7 +42,7 @@
40
42
  },
41
43
  "license": "MIT",
42
44
  "keywords": [
43
- "@mikey-pro/eslint-config",
45
+ "@mikey-pro/eslint-config-vue",
44
46
  "@mikey-pro",
45
47
  "mikey-pro",
46
48
  "mikey",
@@ -49,16 +51,35 @@
49
51
  "eslintconfig",
50
52
  "eslint",
51
53
  "config",
54
+ "vue",
52
55
  "style-guide",
53
56
  "style",
54
57
  "guide",
55
- "vue"
58
+ "eslint-9",
59
+ "flat-config"
56
60
  ],
57
61
  "author": "Mikl Wolfe <wolfe@mikl.io> (https://mikl.io)",
58
62
  "engines": {
59
- "node": ">=18.0.0"
63
+ "node": ">=18.0.0",
64
+ "npm": ">=9.0.0",
65
+ "pnpm": ">=8.0.0",
66
+ "yarn": ">=4.0.0"
60
67
  },
61
68
  "browserslist": [
62
69
  "defaults"
63
- ]
70
+ ],
71
+ "exports": {
72
+ ".": {
73
+ "import": "./index.js",
74
+ "require": "./index.js"
75
+ },
76
+ "./flat": {
77
+ "import": "./flat.js",
78
+ "require": "./flat.js"
79
+ },
80
+ "./legacy": {
81
+ "import": "./legacy.js",
82
+ "require": "./legacy.js"
83
+ }
84
+ }
64
85
  }