@kouts/eslint-config 3.0.3 → 3.0.4
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 +62 -0
- package/dist/index.cjs +59 -0
- package/dist/index.js +59 -0
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -112,6 +112,68 @@ Ad the following settings to your VS Code project settings for autofix on save:
|
|
|
112
112
|
- [eslint-plugin-simple-import-sort](https://github.com/lydell/eslint-plugin-simple-import-sort) for auto-fixing imports order
|
|
113
113
|
- [eslint-plugin-vitest](https://github.com/vitest-dev/eslint-plugin-vitest) for linting Vitest test files
|
|
114
114
|
|
|
115
|
+
## Vue-specific Rules
|
|
116
|
+
|
|
117
|
+
This configuration extends the [ESLint plugin Vue recommended preset](https://eslint.vuejs.org/rules/#priority-c-recommended-potentially-dangerous-patterns) but makes several modifications to enhance code quality and consistency in Vue components.
|
|
118
|
+
|
|
119
|
+
### Disabled Rules
|
|
120
|
+
|
|
121
|
+
- `vue/max-attributes-per-line`: Turned off to allow flexibility in attribute formatting
|
|
122
|
+
- `vue/singleline-html-element-content-newline`: Turned off for cleaner code with fewer line breaks
|
|
123
|
+
|
|
124
|
+
### Strengthened Rules (set to 'error')
|
|
125
|
+
|
|
126
|
+
- `vue/attributes-order`: Enforces consistent order of component attributes
|
|
127
|
+
- `vue/block-order`: Enforces consistent order of component blocks
|
|
128
|
+
- `vue/no-lone-template`: Prevents unnecessary template wrappers
|
|
129
|
+
- `vue/no-multiple-slot-args`: Prevents passing multiple arguments to slots
|
|
130
|
+
- `vue/no-v-html`: Prevents use of v-html to mitigate XSS risks
|
|
131
|
+
- `vue/order-in-components`: Enforces consistent order of component options
|
|
132
|
+
- `vue/this-in-template`: Prevents usage of this in templates
|
|
133
|
+
- `vue/require-prop-types`: Requires type definitions for props
|
|
134
|
+
- `vue/component-name-in-template-casing`: Enforces PascalCase for component names in templates
|
|
135
|
+
- `vue/no-static-inline-styles`: Prevents inline styles in templates
|
|
136
|
+
- `vue/require-explicit-emits`: Requires explicit emit declarations
|
|
137
|
+
- `vue/require-name-property`: Requires components to have a name property
|
|
138
|
+
- `vue/html-self-closing`: Enforces self-closing style for components with no content
|
|
139
|
+
- `vue/dot-notation`: Enforces dot notation where possible in templates
|
|
140
|
+
|
|
141
|
+
### Custom Vue Rules
|
|
142
|
+
|
|
143
|
+
- `kouts/vue-require-name-in-setup`: Enforces that Vue components using `<script setup>` must have a component name.
|
|
144
|
+
|
|
145
|
+
### Customizing/Disabling Vue Rules
|
|
146
|
+
|
|
147
|
+
You can customize or disable any of these rules in your ESLint config:
|
|
148
|
+
|
|
149
|
+
```js
|
|
150
|
+
// eslint.config.js
|
|
151
|
+
import { config } from '@kouts/eslint-config'
|
|
152
|
+
|
|
153
|
+
export default [
|
|
154
|
+
...config(),
|
|
155
|
+
{
|
|
156
|
+
rules: {
|
|
157
|
+
// Disable custom rule
|
|
158
|
+
'kouts/vue-require-name-in-setup': 'off',
|
|
159
|
+
|
|
160
|
+
// Modify strengthened Vue rules
|
|
161
|
+
'vue/attributes-order': 'warn',
|
|
162
|
+
'vue/no-v-html': 'off',
|
|
163
|
+
|
|
164
|
+
// Re-enable rules that were turned off
|
|
165
|
+
'vue/max-attributes-per-line': [
|
|
166
|
+
'error',
|
|
167
|
+
{
|
|
168
|
+
singleline: { max: 3 },
|
|
169
|
+
multiline: { max: 1 },
|
|
170
|
+
},
|
|
171
|
+
],
|
|
172
|
+
},
|
|
173
|
+
},
|
|
174
|
+
]
|
|
175
|
+
```
|
|
176
|
+
|
|
115
177
|
## License
|
|
116
178
|
|
|
117
179
|
[MIT](http://opensource.org/licenses/MIT)
|
package/dist/index.cjs
CHANGED
|
@@ -8,6 +8,55 @@ var pluginSimpleImportSort = require('eslint-plugin-simple-import-sort');
|
|
|
8
8
|
var neostandard = require('neostandard');
|
|
9
9
|
var pluginVue = require('eslint-plugin-vue');
|
|
10
10
|
|
|
11
|
+
const rule = {
|
|
12
|
+
meta: {
|
|
13
|
+
type: "suggestion",
|
|
14
|
+
docs: {
|
|
15
|
+
description: "Require defineOptions with name attribute in script setup Vue components",
|
|
16
|
+
category: "Best Practices",
|
|
17
|
+
recommended: true
|
|
18
|
+
},
|
|
19
|
+
schema: []
|
|
20
|
+
},
|
|
21
|
+
create(context) {
|
|
22
|
+
let hasDefineOptionsWithName = false;
|
|
23
|
+
return {
|
|
24
|
+
// We'll assume every Vue file with script setup needs a defineOptions name
|
|
25
|
+
// Check for defineOptions function calls
|
|
26
|
+
'CallExpression[callee.name="defineOptions"]'(node) {
|
|
27
|
+
if (node.arguments?.length && node.arguments[0]?.type === "ObjectExpression") {
|
|
28
|
+
const properties = node.arguments[0].properties || [];
|
|
29
|
+
for (const prop of properties) {
|
|
30
|
+
if (prop.type === "Property" && prop.key?.type === "Identifier" && prop.key?.name === "name") {
|
|
31
|
+
hasDefineOptionsWithName = true;
|
|
32
|
+
break;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
// At the end of the file, report if we don't have defineOptions with name
|
|
38
|
+
"Program:exit"(node) {
|
|
39
|
+
const filename = context.physicalFilename;
|
|
40
|
+
const isVueFile = filename.endsWith(".vue");
|
|
41
|
+
if (isVueFile && !hasDefineOptionsWithName) {
|
|
42
|
+
const sourceCode = context.sourceCode.getText();
|
|
43
|
+
const hasScriptSetup = /<script\s+setup/.test(sourceCode);
|
|
44
|
+
if (hasScriptSetup) {
|
|
45
|
+
context.report({
|
|
46
|
+
node,
|
|
47
|
+
message: 'Component name is required. Add defineOptions({ name: "YourComponentName" }) to your <script setup>'
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
var customRules = {
|
|
57
|
+
"vue-require-name-in-setup": rule
|
|
58
|
+
};
|
|
59
|
+
|
|
11
60
|
const typescript = [
|
|
12
61
|
...neostandard.plugins["typescript-eslint"].configs.recommended,
|
|
13
62
|
{
|
|
@@ -71,6 +120,8 @@ const vue = (options) => {
|
|
|
71
120
|
files: ["*.vue", "**/*.vue"],
|
|
72
121
|
...languageOptions,
|
|
73
122
|
rules: {
|
|
123
|
+
// Custom rules
|
|
124
|
+
"kouts/vue-require-name-in-setup": "error",
|
|
74
125
|
// Overrides for vue/(vue3-)recommended preset
|
|
75
126
|
"vue/max-attributes-per-line": "off",
|
|
76
127
|
"vue/singleline-html-element-content-newline": "off",
|
|
@@ -113,6 +164,7 @@ const vue = (options) => {
|
|
|
113
164
|
return config;
|
|
114
165
|
};
|
|
115
166
|
|
|
167
|
+
const customRulesPlugin = { name: "kouts", rules: customRules };
|
|
116
168
|
const config = (options) => {
|
|
117
169
|
const opts = {
|
|
118
170
|
noJsx: true,
|
|
@@ -125,6 +177,13 @@ const config = (options) => {
|
|
|
125
177
|
...options
|
|
126
178
|
};
|
|
127
179
|
const linterConfig = [
|
|
180
|
+
// Custom rules plugin
|
|
181
|
+
{
|
|
182
|
+
name: "kouts/custom-rules",
|
|
183
|
+
plugins: {
|
|
184
|
+
kouts: customRulesPlugin
|
|
185
|
+
}
|
|
186
|
+
},
|
|
128
187
|
{
|
|
129
188
|
name: "kouts/ignores",
|
|
130
189
|
ignores: [
|
package/dist/index.js
CHANGED
|
@@ -7,6 +7,55 @@ import neostandard, { plugins, resolveIgnoresFromGitignore } from 'neostandard';
|
|
|
7
7
|
export { plugins } from 'neostandard';
|
|
8
8
|
import pluginVue from 'eslint-plugin-vue';
|
|
9
9
|
|
|
10
|
+
const rule = {
|
|
11
|
+
meta: {
|
|
12
|
+
type: "suggestion",
|
|
13
|
+
docs: {
|
|
14
|
+
description: "Require defineOptions with name attribute in script setup Vue components",
|
|
15
|
+
category: "Best Practices",
|
|
16
|
+
recommended: true
|
|
17
|
+
},
|
|
18
|
+
schema: []
|
|
19
|
+
},
|
|
20
|
+
create(context) {
|
|
21
|
+
let hasDefineOptionsWithName = false;
|
|
22
|
+
return {
|
|
23
|
+
// We'll assume every Vue file with script setup needs a defineOptions name
|
|
24
|
+
// Check for defineOptions function calls
|
|
25
|
+
'CallExpression[callee.name="defineOptions"]'(node) {
|
|
26
|
+
if (node.arguments?.length && node.arguments[0]?.type === "ObjectExpression") {
|
|
27
|
+
const properties = node.arguments[0].properties || [];
|
|
28
|
+
for (const prop of properties) {
|
|
29
|
+
if (prop.type === "Property" && prop.key?.type === "Identifier" && prop.key?.name === "name") {
|
|
30
|
+
hasDefineOptionsWithName = true;
|
|
31
|
+
break;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
// At the end of the file, report if we don't have defineOptions with name
|
|
37
|
+
"Program:exit"(node) {
|
|
38
|
+
const filename = context.physicalFilename;
|
|
39
|
+
const isVueFile = filename.endsWith(".vue");
|
|
40
|
+
if (isVueFile && !hasDefineOptionsWithName) {
|
|
41
|
+
const sourceCode = context.sourceCode.getText();
|
|
42
|
+
const hasScriptSetup = /<script\s+setup/.test(sourceCode);
|
|
43
|
+
if (hasScriptSetup) {
|
|
44
|
+
context.report({
|
|
45
|
+
node,
|
|
46
|
+
message: 'Component name is required. Add defineOptions({ name: "YourComponentName" }) to your <script setup>'
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
var customRules = {
|
|
56
|
+
"vue-require-name-in-setup": rule
|
|
57
|
+
};
|
|
58
|
+
|
|
10
59
|
const typescript = [
|
|
11
60
|
...plugins["typescript-eslint"].configs.recommended,
|
|
12
61
|
{
|
|
@@ -70,6 +119,8 @@ const vue = (options) => {
|
|
|
70
119
|
files: ["*.vue", "**/*.vue"],
|
|
71
120
|
...languageOptions,
|
|
72
121
|
rules: {
|
|
122
|
+
// Custom rules
|
|
123
|
+
"kouts/vue-require-name-in-setup": "error",
|
|
73
124
|
// Overrides for vue/(vue3-)recommended preset
|
|
74
125
|
"vue/max-attributes-per-line": "off",
|
|
75
126
|
"vue/singleline-html-element-content-newline": "off",
|
|
@@ -112,6 +163,7 @@ const vue = (options) => {
|
|
|
112
163
|
return config;
|
|
113
164
|
};
|
|
114
165
|
|
|
166
|
+
const customRulesPlugin = { name: "kouts", rules: customRules };
|
|
115
167
|
const config = (options) => {
|
|
116
168
|
const opts = {
|
|
117
169
|
noJsx: true,
|
|
@@ -124,6 +176,13 @@ const config = (options) => {
|
|
|
124
176
|
...options
|
|
125
177
|
};
|
|
126
178
|
const linterConfig = [
|
|
179
|
+
// Custom rules plugin
|
|
180
|
+
{
|
|
181
|
+
name: "kouts/custom-rules",
|
|
182
|
+
plugins: {
|
|
183
|
+
kouts: customRulesPlugin
|
|
184
|
+
}
|
|
185
|
+
},
|
|
127
186
|
{
|
|
128
187
|
name: "kouts/ignores",
|
|
129
188
|
ignores: [
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kouts/eslint-config",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "3.0.
|
|
5
|
-
"packageManager": "pnpm@10.
|
|
4
|
+
"version": "3.0.4",
|
|
5
|
+
"packageManager": "pnpm@10.10.0",
|
|
6
6
|
"engines": {
|
|
7
7
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
|
8
8
|
},
|
|
@@ -70,13 +70,13 @@
|
|
|
70
70
|
"url": "git+https://github.com/kouts/eslint-config.git"
|
|
71
71
|
},
|
|
72
72
|
"dependencies": {
|
|
73
|
-
"@eslint/js": "^9.
|
|
74
|
-
"@vitest/eslint-plugin": "^1.1.
|
|
73
|
+
"@eslint/js": "^9.26.0",
|
|
74
|
+
"@vitest/eslint-plugin": "^1.1.44",
|
|
75
75
|
"eslint-config-prettier": "^10.1.2",
|
|
76
76
|
"eslint-plugin-html": "^8.1.2",
|
|
77
77
|
"eslint-plugin-prettier": "^5.2.6",
|
|
78
78
|
"eslint-plugin-simple-import-sort": "^12.1.1",
|
|
79
|
-
"eslint-plugin-vue": "^10.
|
|
79
|
+
"eslint-plugin-vue": "^10.1.0",
|
|
80
80
|
"neostandard": "^0.12.1",
|
|
81
81
|
"prettier": "^3.5.3"
|
|
82
82
|
},
|
|
@@ -85,8 +85,8 @@
|
|
|
85
85
|
"@commitlint/config-conventional": "^19.8.0",
|
|
86
86
|
"@semantic-release/changelog": "^6.0.3",
|
|
87
87
|
"@semantic-release/git": "^10.0.1",
|
|
88
|
-
"@types/node": "^22.15.
|
|
89
|
-
"eslint": "^9.
|
|
88
|
+
"@types/node": "^22.15.3",
|
|
89
|
+
"eslint": "^9.26.0",
|
|
90
90
|
"husky": "^9.1.7",
|
|
91
91
|
"lint-staged": "^15.5.1",
|
|
92
92
|
"pkgroll": "^2.12.2",
|