@kikiutils/eslint-config 9.3.1 → 10.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/README.md +8 -0
- package/dist/{internals → _internals}/plugins.d.ts.map +1 -1
- package/dist/{internals → _internals}/plugins.js +1 -1
- package/dist/_internals/plugins.js.map +1 -0
- package/dist/_internals/rules/compact-iteration-layout.d.ts.map +1 -0
- package/dist/{internals → _internals}/rules/compact-iteration-layout.js +1 -1
- package/dist/_internals/rules/compact-iteration-layout.js.map +1 -0
- package/dist/_internals/rules/consistent-condition-layout.d.ts.map +1 -0
- package/dist/{internals → _internals}/rules/consistent-condition-layout.js +1 -1
- package/dist/_internals/rules/consistent-condition-layout.js.map +1 -0
- package/dist/_internals/rules/consistent-parameter-layout.d.ts.map +1 -0
- package/dist/_internals/rules/consistent-parameter-layout.js +137 -0
- package/dist/_internals/rules/consistent-parameter-layout.js.map +1 -0
- package/dist/_internals/rules/statement-padding.d.ts.map +1 -0
- package/dist/{internals → _internals}/rules/statement-padding.js +22 -12
- package/dist/_internals/rules/statement-padding.js.map +1 -0
- package/dist/_internals/type-aware.d.ts +3 -0
- package/dist/_internals/type-aware.d.ts.map +1 -0
- package/dist/_internals/type-aware.js +25 -0
- package/dist/_internals/type-aware.js.map +1 -0
- package/dist/_internals/utils.d.ts.map +1 -0
- package/dist/{internals → _internals}/utils.js +1 -1
- package/dist/_internals/utils.js.map +1 -0
- package/dist/base.d.ts.map +1 -1
- package/dist/base.js +44 -17
- package/dist/base.js.map +1 -1
- package/dist/style.js +1 -5
- package/dist/style.js.map +1 -1
- package/dist/vue.d.ts.map +1 -1
- package/dist/vue.js +8 -4
- package/dist/vue.js.map +1 -1
- package/package.json +19 -70
- package/src/_internals/rules/consistent-parameter-layout.ts +244 -0
- package/src/{internals → _internals}/rules/statement-padding.ts +33 -22
- package/src/_internals/type-aware.ts +28 -0
- package/src/base.ts +67 -24
- package/src/style.ts +1 -2
- package/src/vue.ts +11 -4
- package/dist/internals/plugins.js.map +0 -1
- package/dist/internals/rules/compact-iteration-layout.d.ts.map +0 -1
- package/dist/internals/rules/compact-iteration-layout.js.map +0 -1
- package/dist/internals/rules/consistent-condition-layout.d.ts.map +0 -1
- package/dist/internals/rules/consistent-condition-layout.js.map +0 -1
- package/dist/internals/rules/consistent-parameter-layout.d.ts.map +0 -1
- package/dist/internals/rules/consistent-parameter-layout.js +0 -90
- package/dist/internals/rules/consistent-parameter-layout.js.map +0 -1
- package/dist/internals/rules/statement-padding.d.ts.map +0 -1
- package/dist/internals/rules/statement-padding.js.map +0 -1
- package/dist/internals/utils.d.ts.map +0 -1
- package/dist/internals/utils.js.map +0 -1
- package/src/internals/rules/consistent-parameter-layout.ts +0 -163
- /package/dist/{internals → _internals}/plugins.d.ts +0 -0
- /package/dist/{internals → _internals}/rules/compact-iteration-layout.d.ts +0 -0
- /package/dist/{internals → _internals}/rules/consistent-condition-layout.d.ts +0 -0
- /package/dist/{internals → _internals}/rules/consistent-parameter-layout.d.ts +0 -0
- /package/dist/{internals → _internals}/rules/statement-padding.d.ts +0 -0
- /package/dist/{internals → _internals}/utils.d.ts +0 -0
- /package/src/{internals → _internals}/plugins.ts +0 -0
- /package/src/{internals → _internals}/rules/compact-iteration-layout.ts +0 -0
- /package/src/{internals → _internals}/rules/consistent-condition-layout.ts +0 -0
- /package/src/{internals → _internals}/utils.ts +0 -0
package/dist/style.js
CHANGED
|
@@ -14,11 +14,7 @@ function createPrettierCssConfig(parser) {
|
|
|
14
14
|
};
|
|
15
15
|
}
|
|
16
16
|
function createStyleFilesConfigs() {
|
|
17
|
-
return [
|
|
18
|
-
createPrettierCssConfig("css"),
|
|
19
|
-
createPrettierCssConfig("sass"),
|
|
20
|
-
createPrettierCssConfig("scss")
|
|
21
|
-
];
|
|
17
|
+
return [createPrettierCssConfig("css"), createPrettierCssConfig("scss")];
|
|
22
18
|
}
|
|
23
19
|
export { createStyleFilesConfigs };
|
|
24
20
|
|
package/dist/style.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"style.js","names":[],"sources":["../src/style.ts"],"sourcesContent":["import type { TypedFlatConfigItem } from '@antfu/eslint-config';\nimport format from 'eslint-plugin-format';\n\nfunction createPrettierCssConfig(parser: 'css' | '
|
|
1
|
+
{"version":3,"file":"style.js","names":[],"sources":["../src/style.ts"],"sourcesContent":["import type { TypedFlatConfigItem } from '@antfu/eslint-config';\nimport format from 'eslint-plugin-format';\n\nfunction createPrettierCssConfig(parser: 'css' | 'scss'): TypedFlatConfigItem {\n return {\n files: [`**/*.${parser}`],\n languageOptions: { parser: format.parserPlain },\n plugins: { format },\n rules: {\n 'format/prettier': [\n 'error',\n {\n parser,\n printWidth: 120,\n singleQuote: true,\n tabWidth: 4,\n },\n ],\n },\n };\n}\n\nexport function createStyleFilesConfigs(): TypedFlatConfigItem[] {\n return [\n createPrettierCssConfig('css'),\n createPrettierCssConfig('scss'),\n ];\n}\n"],"mappings":";;AAGA,SAAS,wBAAwB,QAA6C;CAC1E,OAAO;EACH,OAAO,CAAC,QAAQ,QAAQ;EACxB,iBAAiB,EAAE,QAAQ,OAAO,YAAY;EAC9C,SAAS,EAAE,OAAO;EAClB,OAAO,EACH,mBAAmB,CACf,SACA;GACI;GACA,YAAY;GACZ,aAAa;GACb,UAAU;EACd,CACJ,EACJ;CACJ;AACJ;AAEA,SAAgB,0BAAiD;CAC7D,OAAO,CACH,wBAAwB,KAAK,GAC7B,wBAAwB,MAAM,CAClC;AACJ"}
|
package/dist/vue.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vue.d.ts","names":[],"sources":["../src/vue.ts"],"mappings":";
|
|
1
|
+
{"version":3,"file":"vue.d.ts","names":[],"sources":["../src/vue.ts"],"mappings":";wBAUgB,gBAAgB,+BAAuC"}
|
package/dist/vue.js
CHANGED
|
@@ -1,20 +1,24 @@
|
|
|
1
|
-
import { customPlugins } from "./
|
|
1
|
+
import { customPlugins } from "./_internals/plugins.js";
|
|
2
|
+
import { createTypeAwareConfig } from "./_internals/type-aware.js";
|
|
2
3
|
import { createBaseRules } from "./base.js";
|
|
3
4
|
import promise from "eslint-plugin-promise";
|
|
4
5
|
import kikiutilsEslintPluginVue from "@kikiutils/eslint-plugin-vue";
|
|
5
|
-
import
|
|
6
|
+
import betterTailwindcss from "eslint-plugin-better-tailwindcss";
|
|
6
7
|
// src/vue.ts
|
|
7
8
|
function createVueConfig(environment = "node") {
|
|
9
|
+
const typeAwareConfig = createTypeAwareConfig();
|
|
8
10
|
return {
|
|
9
11
|
files: ["**/*.vue"],
|
|
12
|
+
languageOptions: typeAwareConfig.languageOptions,
|
|
10
13
|
plugins: {
|
|
11
14
|
"@kikiutils/vue": kikiutilsEslintPluginVue,
|
|
12
|
-
"better-tailwindcss":
|
|
15
|
+
"better-tailwindcss": betterTailwindcss,
|
|
13
16
|
"kikiutils": customPlugins,
|
|
14
17
|
promise
|
|
15
18
|
},
|
|
16
19
|
rules: {
|
|
17
20
|
...createBaseRules(environment),
|
|
21
|
+
...typeAwareConfig.rules,
|
|
18
22
|
"@kikiutils/vue/attributes-order": ["error", {
|
|
19
23
|
alphabetical: true,
|
|
20
24
|
alphabeticalEnhanced: true
|
|
@@ -29,6 +33,7 @@ function createVueConfig(environment = "node") {
|
|
|
29
33
|
"better-tailwindcss/no-duplicate-classes": "error",
|
|
30
34
|
"better-tailwindcss/no-unnecessary-whitespace": "error",
|
|
31
35
|
"style/max-len": "off",
|
|
36
|
+
"ts/array-type": ["error", { default: "array-simple" }],
|
|
32
37
|
"vue/attribute-hyphenation": "error",
|
|
33
38
|
"vue/attributes-order": "off",
|
|
34
39
|
"vue/block-order": ["error", { order: [
|
|
@@ -60,7 +65,6 @@ function createVueConfig(environment = "node") {
|
|
|
60
65
|
"vue/no-template-target-blank": "error",
|
|
61
66
|
"vue/no-v-html": "error",
|
|
62
67
|
"vue/prefer-define-options": "error",
|
|
63
|
-
"vue/prefer-separate-static-class": "error",
|
|
64
68
|
"vue/require-explicit-emits": "error",
|
|
65
69
|
"vue/require-typed-ref": "error"
|
|
66
70
|
}
|
package/dist/vue.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vue.js","names":[],"sources":["../src/vue.ts"],"sourcesContent":["import type { TypedFlatConfigItem } from '@antfu/eslint-config';\nimport kikiutilsEslintPluginVue from '@kikiutils/eslint-plugin-vue';\nimport
|
|
1
|
+
{"version":3,"file":"vue.js","names":[],"sources":["../src/vue.ts"],"sourcesContent":["import type { TypedFlatConfigItem } from '@antfu/eslint-config';\nimport kikiutilsEslintPluginVue from '@kikiutils/eslint-plugin-vue';\nimport betterTailwindcss from 'eslint-plugin-better-tailwindcss';\n// @ts-expect-error No declare file.\nimport promise from 'eslint-plugin-promise';\n\nimport { customPlugins } from './_internals/plugins';\nimport { createTypeAwareConfig } from './_internals/type-aware';\nimport { createBaseRules } from './base';\n\nexport function createVueConfig(environment: 'bun' | 'node' = 'node'): TypedFlatConfigItem {\n const typeAwareConfig = createTypeAwareConfig();\n return {\n files: ['**/*.vue'],\n languageOptions: typeAwareConfig.languageOptions,\n plugins: {\n '@kikiutils/vue': kikiutilsEslintPluginVue,\n 'better-tailwindcss': betterTailwindcss,\n 'kikiutils': customPlugins,\n promise,\n },\n rules: {\n ...createBaseRules(environment),\n ...typeAwareConfig.rules,\n '@kikiutils/vue/attributes-order': [\n 'error',\n {\n alphabetical: true,\n alphabeticalEnhanced: true,\n },\n ],\n '@kikiutils/vue/class-hex-color-case': 'error',\n 'better-tailwindcss/enforce-consistent-class-order': 'error',\n 'better-tailwindcss/enforce-consistent-important-position': 'error',\n 'better-tailwindcss/enforce-consistent-variable-syntax': 'error',\n 'better-tailwindcss/enforce-consistent-variant-order': 'error',\n 'better-tailwindcss/enforce-shorthand-classes': 'error',\n 'better-tailwindcss/no-deprecated-classes': 'warn',\n 'better-tailwindcss/no-duplicate-classes': 'error',\n 'better-tailwindcss/no-unnecessary-whitespace': 'error',\n 'style/max-len': 'off',\n 'ts/array-type': [\n 'error',\n { default: 'array-simple' },\n ],\n 'vue/attribute-hyphenation': 'error',\n 'vue/attributes-order': 'off',\n 'vue/block-order': [\n 'error',\n {\n order: [\n 'template',\n 'script',\n 'style',\n ],\n },\n ],\n 'vue/component-api-style': 'error',\n 'vue/define-emits-declaration': 'error',\n 'vue/define-props-declaration': 'error',\n 'vue/enforce-style-attribute': 'error',\n 'vue/html-closing-bracket-newline': 'error',\n 'vue/html-closing-bracket-spacing': 'error',\n 'vue/html-indent': [\n 'error',\n 4,\n ],\n 'vue/max-attributes-per-line': [\n 'error',\n {\n multiline: 1,\n singleline: 1,\n },\n ],\n 'vue/max-len': [\n 'warn',\n {\n code: 120,\n comments: 120,\n template: 120,\n },\n ],\n 'vue/no-dupe-keys': 'error',\n 'vue/no-lone-template': 'error',\n 'vue/no-multi-spaces': 'error',\n 'vue/no-multiple-objects-in-class': 'error',\n 'vue/no-root-v-if': 'error',\n 'vue/no-template-target-blank': 'error',\n 'vue/no-v-html': 'error',\n 'vue/prefer-define-options': 'error',\n 'vue/require-explicit-emits': 'error',\n 'vue/require-typed-ref': 'error',\n },\n };\n}\n"],"mappings":";;;;;;;AAUA,SAAgB,gBAAgB,cAA8B,QAA6B;CACvF,MAAM,kBAAkB,sBAAsB;CAC9C,OAAO;EACH,OAAO,CAAC,UAAU;EAClB,iBAAiB,gBAAgB;EACjC,SAAS;GACL,kBAAkB;GAClB,sBAAsB;GACtB,aAAa;GACb;EACJ;EACA,OAAO;GACH,GAAG,gBAAgB,WAAW;GAC9B,GAAG,gBAAgB;GACnB,mCAAmC,CAC/B,SACA;IACI,cAAc;IACd,sBAAsB;GAC1B,CACJ;GACA,uCAAuC;GACvC,qDAAqD;GACrD,4DAA4D;GAC5D,yDAAyD;GACzD,uDAAuD;GACvD,gDAAgD;GAChD,4CAA4C;GAC5C,2CAA2C;GAC3C,gDAAgD;GAChD,iBAAiB;GACjB,iBAAiB,CACb,SACA,EAAE,SAAS,eAAe,CAC9B;GACA,6BAA6B;GAC7B,wBAAwB;GACxB,mBAAmB,CACf,SACA,EACI,OAAO;IACH;IACA;IACA;GACJ,EACJ,CACJ;GACA,2BAA2B;GAC3B,gCAAgC;GAChC,gCAAgC;GAChC,+BAA+B;GAC/B,oCAAoC;GACpC,oCAAoC;GACpC,mBAAmB,CACf,SACA,CACJ;GACA,+BAA+B,CAC3B,SACA;IACI,WAAW;IACX,YAAY;GAChB,CACJ;GACA,eAAe,CACX,QACA;IACI,MAAM;IACN,UAAU;IACV,UAAU;GACd,CACJ;GACA,oBAAoB;GACpB,wBAAwB;GACxB,uBAAuB;GACvB,oCAAoC;GACpC,oBAAoB;GACpB,gCAAgC;GAChC,iBAAiB;GACjB,6BAA6B;GAC7B,8BAA8B;GAC9B,yBAAyB;EAC7B;CACJ;AACJ"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kikiutils/eslint-config",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "10.0.0",
|
|
5
5
|
"description": "Using antfu/eslint-config as a base for eslint-config, slightly modified the settings and added additional plugins, mainly for my own use.",
|
|
6
6
|
"author": "kiki-kanri",
|
|
7
7
|
"license": "MIT",
|
|
@@ -12,38 +12,10 @@
|
|
|
12
12
|
"keywords": [],
|
|
13
13
|
"sideEffects": false,
|
|
14
14
|
"exports": {
|
|
15
|
-
"./
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
},
|
|
20
|
-
"./internals/rules/compact-iteration-layout": {
|
|
21
|
-
"types": null,
|
|
22
|
-
"import": null,
|
|
23
|
-
"require": null
|
|
24
|
-
},
|
|
25
|
-
"./internals/rules/consistent-condition-layout": {
|
|
26
|
-
"types": null,
|
|
27
|
-
"import": null,
|
|
28
|
-
"require": null
|
|
29
|
-
},
|
|
30
|
-
"./internals/rules/consistent-parameter-layout": {
|
|
31
|
-
"types": null,
|
|
32
|
-
"import": null,
|
|
33
|
-
"require": null
|
|
34
|
-
},
|
|
35
|
-
"./internals/rules/statement-padding": {
|
|
36
|
-
"types": null,
|
|
37
|
-
"import": null,
|
|
38
|
-
"require": null
|
|
39
|
-
},
|
|
40
|
-
"./internals/utils": {
|
|
41
|
-
"types": null,
|
|
42
|
-
"import": null,
|
|
43
|
-
"require": null
|
|
44
|
-
},
|
|
45
|
-
"./package.json": "./package.json",
|
|
46
|
-
"./*": "./dist/*.js"
|
|
15
|
+
"./base": "./dist/base.js",
|
|
16
|
+
"./style": "./dist/style.js",
|
|
17
|
+
"./vue": "./dist/vue.js",
|
|
18
|
+
"./package.json": "./package.json"
|
|
47
19
|
},
|
|
48
20
|
"files": [
|
|
49
21
|
"./dist",
|
|
@@ -67,61 +39,38 @@
|
|
|
67
39
|
},
|
|
68
40
|
"peerDependencies": {
|
|
69
41
|
"@antfu/eslint-config": "^10.0.0",
|
|
70
|
-
"@eslint/css": "^2.0.0",
|
|
71
|
-
"@html-eslint/parser": ">=0.67.0",
|
|
72
|
-
"@kikiutils/eslint-plugin-vue": "^10.10.0",
|
|
73
42
|
"eslint": "^10.13.0",
|
|
74
|
-
"
|
|
75
|
-
"eslint-plugin-format": ">=2.0.1",
|
|
76
|
-
"tailwind-csstree": "^0.4.1",
|
|
77
|
-
"tailwindcss": "^4.3.3",
|
|
78
|
-
"vue-eslint-parser": "^10.4.1"
|
|
43
|
+
"tailwindcss": "^4.3.3"
|
|
79
44
|
},
|
|
80
45
|
"peerDependenciesMeta": {
|
|
81
|
-
"@eslint/css": {
|
|
82
|
-
"optional": true
|
|
83
|
-
},
|
|
84
|
-
"@html-eslint/parser": {
|
|
85
|
-
"optional": true
|
|
86
|
-
},
|
|
87
|
-
"@kikiutils/eslint-plugin-vue": {
|
|
88
|
-
"optional": true
|
|
89
|
-
},
|
|
90
46
|
"eslint": {
|
|
91
47
|
"optional": true
|
|
92
48
|
},
|
|
93
|
-
"eslint-plugin-better-tailwindcss": {
|
|
94
|
-
"optional": true
|
|
95
|
-
},
|
|
96
|
-
"eslint-plugin-format": {
|
|
97
|
-
"optional": true
|
|
98
|
-
},
|
|
99
|
-
"tailwind-csstree": {
|
|
100
|
-
"optional": true
|
|
101
|
-
},
|
|
102
49
|
"tailwindcss": {
|
|
103
50
|
"optional": true
|
|
104
|
-
},
|
|
105
|
-
"vue-eslint-parser": {
|
|
106
|
-
"optional": true
|
|
107
51
|
}
|
|
108
52
|
},
|
|
109
53
|
"dependencies": {
|
|
110
|
-
"eslint
|
|
54
|
+
"@eslint/css": "^2.0.1",
|
|
55
|
+
"@html-eslint/parser": "^0.67.0",
|
|
56
|
+
"@kikiutils/eslint-plugin-vue": "^10.10.0",
|
|
57
|
+
"eslint-plugin-better-tailwindcss": "^4.10.0",
|
|
58
|
+
"eslint-plugin-format": "^2.0.1",
|
|
59
|
+
"eslint-plugin-promise": "^7.3.0",
|
|
60
|
+
"tailwind-csstree": "^0.4.2",
|
|
61
|
+
"vue-eslint-parser": "^10.4.1"
|
|
111
62
|
},
|
|
112
63
|
"devDependencies": {
|
|
113
64
|
"@antfu/eslint-config": "^10.0.0",
|
|
114
|
-
"@
|
|
65
|
+
"@arethetypeswrong/core": "^0.18.5",
|
|
115
66
|
"@kikiutils/tsconfigs": "^7.0.0",
|
|
116
|
-
"@types/node": "^26.6.
|
|
67
|
+
"@types/node": "^26.6.6",
|
|
117
68
|
"@vitest/coverage-v8": "^5.0.5",
|
|
118
69
|
"changelogen": "^0.6.2",
|
|
119
|
-
"eslint": "^10.
|
|
120
|
-
"
|
|
121
|
-
"eslint-plugin-format": "^2.0.1",
|
|
122
|
-
"knip": "^6.42.1",
|
|
70
|
+
"eslint": "^10.14.0",
|
|
71
|
+
"knip": "^6.44.0",
|
|
123
72
|
"publint": "^0.3.25",
|
|
124
|
-
"tsdown": "^0.23.
|
|
73
|
+
"tsdown": "^0.23.4",
|
|
125
74
|
"typescript": "^6.0.3",
|
|
126
75
|
"unplugin-unused": "^0.6.0",
|
|
127
76
|
"vitest": "^5.0.5"
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
AST,
|
|
3
|
+
Rule,
|
|
4
|
+
} from 'eslint';
|
|
5
|
+
|
|
6
|
+
import type { TokenStore } from '../utils';
|
|
7
|
+
import { defineScriptAndTemplateVisitors } from '../utils';
|
|
8
|
+
|
|
9
|
+
type CallNode = Extract<Rule.Node, { type: 'CallExpression' | 'NewExpression' }> & { typeArguments?: Rule.Node };
|
|
10
|
+
type FunctionNode = Extract<
|
|
11
|
+
Rule.Node,
|
|
12
|
+
{ type: 'ArrowFunctionExpression' | 'FunctionDeclaration' | 'FunctionExpression' }
|
|
13
|
+
>;
|
|
14
|
+
|
|
15
|
+
type ListItem = CallNode['arguments'][number] | FunctionNode['params'][number];
|
|
16
|
+
|
|
17
|
+
export const consistentParameterLayout: Rule.RuleModule = {
|
|
18
|
+
create(context) {
|
|
19
|
+
const compactTestCalls = context.options[0]?.compactTestCalls === true;
|
|
20
|
+
|
|
21
|
+
function createVisitor(tokenStore: TokenStore, isTemplate: boolean): Rule.RuleListener {
|
|
22
|
+
function checkTestCallLayout(node: CallNode): void {
|
|
23
|
+
const items = node.arguments;
|
|
24
|
+
if (!items.length) return;
|
|
25
|
+
const openingParen = tokenStore.getTokenAfter(
|
|
26
|
+
node.typeArguments ?? node.callee,
|
|
27
|
+
(token) => token.type === 'Punctuator' && token.value === '(',
|
|
28
|
+
)!;
|
|
29
|
+
|
|
30
|
+
const closingParen = tokenStore.getLastToken(node)!;
|
|
31
|
+
const previous = tokenStore.getTokenBefore(closingParen)!;
|
|
32
|
+
const gaps: Array<[AST.Token, AST.Token, string]> = [
|
|
33
|
+
[
|
|
34
|
+
openingParen,
|
|
35
|
+
tokenStore.getTokenAfter(openingParen)!,
|
|
36
|
+
'',
|
|
37
|
+
],
|
|
38
|
+
[
|
|
39
|
+
previous,
|
|
40
|
+
closingParen,
|
|
41
|
+
'',
|
|
42
|
+
],
|
|
43
|
+
];
|
|
44
|
+
|
|
45
|
+
for (let index = 1; index < items.length; index++) {
|
|
46
|
+
const comma = tokenStore.getTokensBetween(items[index - 1]!, items[index]!)
|
|
47
|
+
.find((token) => token.type === 'Punctuator' && token.value === ',')!;
|
|
48
|
+
|
|
49
|
+
gaps.push(
|
|
50
|
+
[
|
|
51
|
+
tokenStore.getTokenBefore(comma)!,
|
|
52
|
+
comma,
|
|
53
|
+
'',
|
|
54
|
+
],
|
|
55
|
+
[
|
|
56
|
+
comma,
|
|
57
|
+
tokenStore.getTokenAfter(comma)!,
|
|
58
|
+
' ',
|
|
59
|
+
],
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (previous.value === ',') {
|
|
64
|
+
gaps.push([
|
|
65
|
+
tokenStore.getTokenBefore(previous)!,
|
|
66
|
+
previous,
|
|
67
|
+
'',
|
|
68
|
+
]);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Keep the whole list's layout when a boundary comment prevents safe compaction.
|
|
72
|
+
if (gaps.some(([left, right]) => tokenStore.commentsExistBetween(left, right))) return;
|
|
73
|
+
const multilineGaps = gaps.filter(([left, right]) => left.loc.end.line !== right.loc.start.line);
|
|
74
|
+
if (!multilineGaps.length) return;
|
|
75
|
+
|
|
76
|
+
context.report({
|
|
77
|
+
fix: (fixer) => multilineGaps.map(([
|
|
78
|
+
left,
|
|
79
|
+
right,
|
|
80
|
+
text,
|
|
81
|
+
]) => fixer.replaceTextRange(
|
|
82
|
+
[
|
|
83
|
+
left.range[1],
|
|
84
|
+
right.range[0],
|
|
85
|
+
],
|
|
86
|
+
text,
|
|
87
|
+
)),
|
|
88
|
+
messageId: 'compactTestCall',
|
|
89
|
+
node,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function checkParameterLayout(
|
|
94
|
+
node: CallNode | FunctionNode,
|
|
95
|
+
items: readonly ListItem[],
|
|
96
|
+
): void {
|
|
97
|
+
const first = items[0];
|
|
98
|
+
if (!first) return;
|
|
99
|
+
const isSingleParameter = items.length === 1;
|
|
100
|
+
|
|
101
|
+
// JSX argument layout belongs to the JSX formatting rules.
|
|
102
|
+
const firstType: string = first.type;
|
|
103
|
+
if (isSingleParameter && (firstType === 'JSXElement' || firstType === 'JSXFragment')) return;
|
|
104
|
+
let openingParen;
|
|
105
|
+
if (node.type === 'CallExpression' || node.type === 'NewExpression') {
|
|
106
|
+
openingParen = tokenStore.getTokenAfter(
|
|
107
|
+
node.typeArguments ?? node.callee,
|
|
108
|
+
(token) => token.type === 'Punctuator' && token.value === '(',
|
|
109
|
+
);
|
|
110
|
+
} else {
|
|
111
|
+
openingParen = tokenStore.getTokenBefore(first);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (!openingParen || openingParen.value !== '(') return;
|
|
115
|
+
// An unparenthesized arrow must not borrow its parent's delimiters.
|
|
116
|
+
if (openingParen.range[0] < node.range![0]) return;
|
|
117
|
+
const closingParen = node.type === 'CallExpression' || node.type === 'NewExpression'
|
|
118
|
+
? tokenStore.getLastToken(node)
|
|
119
|
+
: tokenStore.getTokenAfter(items.at(-1)!, (token) => token.value === ')');
|
|
120
|
+
|
|
121
|
+
const next = tokenStore.getTokenAfter(openingParen)!;
|
|
122
|
+
|
|
123
|
+
if (isSingleParameter) {
|
|
124
|
+
if (!closingParen || closingParen.value !== ')') return;
|
|
125
|
+
let previous = tokenStore.getTokenBefore(closingParen)!;
|
|
126
|
+
if (previous.value === ',') previous = tokenStore.getTokenBefore(previous)!;
|
|
127
|
+
if (
|
|
128
|
+
tokenStore.commentsExistBetween(openingParen, next)
|
|
129
|
+
|| tokenStore.commentsExistBetween(previous, closingParen)
|
|
130
|
+
) return;
|
|
131
|
+
|
|
132
|
+
const hasOpeningNewline = openingParen.loc.end.line !== next.loc.start.line;
|
|
133
|
+
const hasClosingNewline = tokenStore.getTokenBefore(closingParen)!.loc.end.line
|
|
134
|
+
!== closingParen.loc.start.line;
|
|
135
|
+
|
|
136
|
+
if (hasOpeningNewline === hasClosingNewline) return;
|
|
137
|
+
|
|
138
|
+
context.report({
|
|
139
|
+
fix: (fixer) => hasOpeningNewline
|
|
140
|
+
? fixer.insertTextBefore(closingParen, '\n')
|
|
141
|
+
: fixer.insertTextAfter(openingParen, '\n'),
|
|
142
|
+
messageId: 'singleBoundary',
|
|
143
|
+
node,
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (!closingParen || openingParen.loc.start.line === closingParen.loc.end.line) return;
|
|
150
|
+
|
|
151
|
+
if (isTemplate) {
|
|
152
|
+
// Script list formatters do not traverse Vue template expressions.
|
|
153
|
+
const newlineOffsets: number[] = [];
|
|
154
|
+
if (openingParen.loc.end.line === next.loc.start.line) newlineOffsets.push(openingParen.range[1]);
|
|
155
|
+
for (let index = 1; index < items.length; index++) {
|
|
156
|
+
const item = items[index]!;
|
|
157
|
+
const comma = tokenStore.getTokensBetween(items[index - 1]!, item)
|
|
158
|
+
.find((token) => token.value === ',');
|
|
159
|
+
|
|
160
|
+
if (comma && comma.loc.end.line === tokenStore.getTokenAfter(comma)!.loc.start.line) {
|
|
161
|
+
newlineOffsets.push(comma.range[1]);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (
|
|
166
|
+
closingParen.value === ')'
|
|
167
|
+
&& tokenStore.getTokenBefore(closingParen)!.loc.end.line === closingParen.loc.start.line
|
|
168
|
+
) newlineOffsets.push(closingParen.range[0]);
|
|
169
|
+
|
|
170
|
+
if (newlineOffsets.length) {
|
|
171
|
+
context.report({
|
|
172
|
+
fix: (fixer) => newlineOffsets.map((offset) => fixer.insertTextBeforeRange(
|
|
173
|
+
[
|
|
174
|
+
offset,
|
|
175
|
+
offset,
|
|
176
|
+
],
|
|
177
|
+
'\n',
|
|
178
|
+
)),
|
|
179
|
+
messageId: 'newline',
|
|
180
|
+
node: first,
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (openingParen.loc.end.line !== next.loc.start.line) return;
|
|
188
|
+
|
|
189
|
+
context.report({
|
|
190
|
+
fix: (fixer) => fixer.insertTextAfter(openingParen, '\n'),
|
|
191
|
+
messageId: 'newline',
|
|
192
|
+
node: first,
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return {
|
|
197
|
+
ArrowFunctionExpression: (node) => checkParameterLayout(node, node.params),
|
|
198
|
+
CallExpression: (node) => {
|
|
199
|
+
const { callee } = node;
|
|
200
|
+
if (compactTestCalls) {
|
|
201
|
+
const target = callee.type === 'MemberExpression'
|
|
202
|
+
&& !callee.computed
|
|
203
|
+
&& callee.property.type === 'Identifier'
|
|
204
|
+
&& callee.property.name === 'concurrent'
|
|
205
|
+
? callee.object
|
|
206
|
+
: callee;
|
|
207
|
+
|
|
208
|
+
if (
|
|
209
|
+
target.type === 'Identifier'
|
|
210
|
+
&& (target.name === 'describe' || target.name === 'it')
|
|
211
|
+
) {
|
|
212
|
+
checkTestCallLayout(node);
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
checkParameterLayout(node, node.arguments);
|
|
218
|
+
},
|
|
219
|
+
FunctionDeclaration: (node) => checkParameterLayout(node, node.params),
|
|
220
|
+
FunctionExpression: (node) => checkParameterLayout(node, node.params),
|
|
221
|
+
NewExpression: (node) => checkParameterLayout(node, node.arguments),
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
return defineScriptAndTemplateVisitors(context.sourceCode, createVisitor);
|
|
226
|
+
},
|
|
227
|
+
meta: {
|
|
228
|
+
docs: { description: 'Keep parameter boundaries consistent, expand multiline lists, and compact test calls.' },
|
|
229
|
+
fixable: 'whitespace',
|
|
230
|
+
messages: {
|
|
231
|
+
compactTestCall: 'Keep test-call arguments beside their parentheses and each other.',
|
|
232
|
+
newline: 'Start a multiline parameter list on a new line.',
|
|
233
|
+
singleBoundary: 'Use matching newline boundaries around a single parameter.',
|
|
234
|
+
},
|
|
235
|
+
schema: [
|
|
236
|
+
{
|
|
237
|
+
additionalProperties: false,
|
|
238
|
+
properties: { compactTestCalls: { type: 'boolean' } },
|
|
239
|
+
type: 'object',
|
|
240
|
+
},
|
|
241
|
+
],
|
|
242
|
+
type: 'layout',
|
|
243
|
+
},
|
|
244
|
+
};
|
|
@@ -10,12 +10,20 @@ export const statementPadding: Rule.RuleModule = {
|
|
|
10
10
|
for (let index = 1; index < statements.length; index++) {
|
|
11
11
|
const previous = statements[index - 1]!;
|
|
12
12
|
const next = statements[index]!;
|
|
13
|
+
if (
|
|
14
|
+
[
|
|
15
|
+
previous,
|
|
16
|
+
next,
|
|
17
|
+
].some((node) =>
|
|
18
|
+
node.type === 'ImportDeclaration'
|
|
19
|
+
|| node.type === 'ExportAllDeclaration'
|
|
20
|
+
|| (node.type === 'ExportNamedDeclaration' && node.source))
|
|
21
|
+
) continue;
|
|
22
|
+
|
|
23
|
+
const previousFirstToken = sourceCode.getFirstToken(previous)!;
|
|
13
24
|
const lastToken = sourceCode.getLastToken(previous)!;
|
|
14
25
|
const firstToken = sourceCode.getFirstToken(next)!;
|
|
15
|
-
const
|
|
16
|
-
const openingLine = sourceCode.lines[firstToken.loc.start.line - 1]!;
|
|
17
|
-
const hasDifferentIndent = /^\s*/.exec(closingLine)![0] !== /^\s*/.exec(openingLine)![0];
|
|
18
|
-
const hasStandaloneClosing = /^[)\]}]+;?$/.test(closingLine.slice(0, lastToken.loc.end.column).trim());
|
|
26
|
+
const isMultiline = previousFirstToken.loc.start.line !== lastToken.loc.end.line;
|
|
19
27
|
const blockNode = previous.type === 'ExportDefaultDeclaration'
|
|
20
28
|
|| previous.type === 'ExportNamedDeclaration'
|
|
21
29
|
? previous.declaration
|
|
@@ -36,24 +44,27 @@ export const statementPadding: Rule.RuleModule = {
|
|
|
36
44
|
'WithStatement',
|
|
37
45
|
].includes(blockNode.type);
|
|
38
46
|
|
|
39
|
-
if (!
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
.slice(lastToken.loc.end.line, firstToken.loc.start.line - 1)
|
|
45
|
-
.some((line, index) => !line.trim() && !comments.some((comment) =>
|
|
46
|
-
comment.loc!.start.line <= lastToken.loc.end.line + index + 1
|
|
47
|
-
&& comment.loc!.end.line >= lastToken.loc.end.line + index + 1))
|
|
48
|
-
) continue;
|
|
47
|
+
if (!isMultiline && !hasBlockClosing) continue;
|
|
48
|
+
let previousEnd = lastToken.range[1];
|
|
49
|
+
let previousEndLine = lastToken.loc.end.line;
|
|
50
|
+
let nextStart = firstToken.range[0];
|
|
51
|
+
let nextStartLine = firstToken.loc.start.line;
|
|
49
52
|
|
|
50
|
-
//
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
+
// Include trailing comments in the previous boundary, not leading comments of the next statement.
|
|
54
|
+
for (const comment of sourceCode.getCommentsBefore(next)) {
|
|
55
|
+
if (comment.loc!.start.line === previousEndLine) {
|
|
56
|
+
previousEnd = comment.range![1];
|
|
57
|
+
previousEndLine = comment.loc!.end.line;
|
|
58
|
+
} else {
|
|
59
|
+
nextStart = comment.range![0];
|
|
60
|
+
nextStartLine = comment.loc!.start.line;
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
53
64
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
65
|
+
if (nextStartLine > previousEndLine + 1) continue;
|
|
66
|
+
const linebreakIndex = sourceCode.text.slice(previousEnd, nextStart).indexOf('\n');
|
|
67
|
+
const offset = linebreakIndex === -1 ? nextStart : previousEnd + linebreakIndex + 1;
|
|
57
68
|
|
|
58
69
|
context.report({
|
|
59
70
|
fix: (fixer) => fixer.insertTextBeforeRange(
|
|
@@ -61,7 +72,7 @@ export const statementPadding: Rule.RuleModule = {
|
|
|
61
72
|
offset,
|
|
62
73
|
offset,
|
|
63
74
|
],
|
|
64
|
-
|
|
75
|
+
linebreakIndex === -1 ? '\n\n' : '\n',
|
|
65
76
|
),
|
|
66
77
|
messageId: 'blankLine',
|
|
67
78
|
node: next,
|
|
@@ -77,7 +88,7 @@ export const statementPadding: Rule.RuleModule = {
|
|
|
77
88
|
};
|
|
78
89
|
},
|
|
79
90
|
meta: {
|
|
80
|
-
docs: { description: 'Separate statements
|
|
91
|
+
docs: { description: 'Separate complete multiline statements and block-ending statements with blank lines.' },
|
|
81
92
|
fixable: 'whitespace',
|
|
82
93
|
messages: { blankLine: 'Add a blank line between these complete statements.' },
|
|
83
94
|
schema: [],
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { TypedFlatConfigItem } from '@antfu/eslint-config';
|
|
2
|
+
|
|
3
|
+
export function createTypeAwareConfig(): TypedFlatConfigItem {
|
|
4
|
+
return {
|
|
5
|
+
languageOptions: {
|
|
6
|
+
parserOptions: {
|
|
7
|
+
projectService: true,
|
|
8
|
+
tsconfigRootDir: process.cwd(),
|
|
9
|
+
},
|
|
10
|
+
},
|
|
11
|
+
rules: {
|
|
12
|
+
'require-await': 'off',
|
|
13
|
+
'ts/await-thenable': 'error',
|
|
14
|
+
'ts/no-base-to-string': 'error',
|
|
15
|
+
'ts/no-floating-promises': 'error',
|
|
16
|
+
'ts/no-for-in-array': 'error',
|
|
17
|
+
'ts/no-misused-promises': 'error',
|
|
18
|
+
'ts/no-misused-spread': 'error',
|
|
19
|
+
'ts/no-unnecessary-type-assertion': 'error',
|
|
20
|
+
'ts/require-await': 'error',
|
|
21
|
+
'ts/return-await': 'error',
|
|
22
|
+
'ts/switch-exhaustiveness-check': [
|
|
23
|
+
'error',
|
|
24
|
+
{ considerDefaultExhaustiveForUnions: true },
|
|
25
|
+
],
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
}
|