@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.
Files changed (61) hide show
  1. package/README.md +8 -0
  2. package/dist/{internals → _internals}/plugins.d.ts.map +1 -1
  3. package/dist/{internals → _internals}/plugins.js +1 -1
  4. package/dist/_internals/plugins.js.map +1 -0
  5. package/dist/_internals/rules/compact-iteration-layout.d.ts.map +1 -0
  6. package/dist/{internals → _internals}/rules/compact-iteration-layout.js +1 -1
  7. package/dist/_internals/rules/compact-iteration-layout.js.map +1 -0
  8. package/dist/_internals/rules/consistent-condition-layout.d.ts.map +1 -0
  9. package/dist/{internals → _internals}/rules/consistent-condition-layout.js +1 -1
  10. package/dist/_internals/rules/consistent-condition-layout.js.map +1 -0
  11. package/dist/_internals/rules/consistent-parameter-layout.d.ts.map +1 -0
  12. package/dist/_internals/rules/consistent-parameter-layout.js +137 -0
  13. package/dist/_internals/rules/consistent-parameter-layout.js.map +1 -0
  14. package/dist/_internals/rules/statement-padding.d.ts.map +1 -0
  15. package/dist/{internals → _internals}/rules/statement-padding.js +22 -12
  16. package/dist/_internals/rules/statement-padding.js.map +1 -0
  17. package/dist/_internals/type-aware.d.ts +3 -0
  18. package/dist/_internals/type-aware.d.ts.map +1 -0
  19. package/dist/_internals/type-aware.js +25 -0
  20. package/dist/_internals/type-aware.js.map +1 -0
  21. package/dist/_internals/utils.d.ts.map +1 -0
  22. package/dist/{internals → _internals}/utils.js +1 -1
  23. package/dist/_internals/utils.js.map +1 -0
  24. package/dist/base.d.ts.map +1 -1
  25. package/dist/base.js +44 -17
  26. package/dist/base.js.map +1 -1
  27. package/dist/style.js +1 -5
  28. package/dist/style.js.map +1 -1
  29. package/dist/vue.d.ts.map +1 -1
  30. package/dist/vue.js +8 -4
  31. package/dist/vue.js.map +1 -1
  32. package/package.json +19 -70
  33. package/src/_internals/rules/consistent-parameter-layout.ts +244 -0
  34. package/src/{internals → _internals}/rules/statement-padding.ts +33 -22
  35. package/src/_internals/type-aware.ts +28 -0
  36. package/src/base.ts +67 -24
  37. package/src/style.ts +1 -2
  38. package/src/vue.ts +11 -4
  39. package/dist/internals/plugins.js.map +0 -1
  40. package/dist/internals/rules/compact-iteration-layout.d.ts.map +0 -1
  41. package/dist/internals/rules/compact-iteration-layout.js.map +0 -1
  42. package/dist/internals/rules/consistent-condition-layout.d.ts.map +0 -1
  43. package/dist/internals/rules/consistent-condition-layout.js.map +0 -1
  44. package/dist/internals/rules/consistent-parameter-layout.d.ts.map +0 -1
  45. package/dist/internals/rules/consistent-parameter-layout.js +0 -90
  46. package/dist/internals/rules/consistent-parameter-layout.js.map +0 -1
  47. package/dist/internals/rules/statement-padding.d.ts.map +0 -1
  48. package/dist/internals/rules/statement-padding.js.map +0 -1
  49. package/dist/internals/utils.d.ts.map +0 -1
  50. package/dist/internals/utils.js.map +0 -1
  51. package/src/internals/rules/consistent-parameter-layout.ts +0 -163
  52. /package/dist/{internals → _internals}/plugins.d.ts +0 -0
  53. /package/dist/{internals → _internals}/rules/compact-iteration-layout.d.ts +0 -0
  54. /package/dist/{internals → _internals}/rules/consistent-condition-layout.d.ts +0 -0
  55. /package/dist/{internals → _internals}/rules/consistent-parameter-layout.d.ts +0 -0
  56. /package/dist/{internals → _internals}/rules/statement-padding.d.ts +0 -0
  57. /package/dist/{internals → _internals}/utils.d.ts +0 -0
  58. /package/src/{internals → _internals}/plugins.ts +0 -0
  59. /package/src/{internals → _internals}/rules/compact-iteration-layout.ts +0 -0
  60. /package/src/{internals → _internals}/rules/consistent-condition-layout.ts +0 -0
  61. /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' | 'sass' | '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('sass'),\n createPrettierCssConfig('scss'),\n ];\n}\n"],"mappings":";;AAGA,SAAS,wBAAwB,QAAsD;CACnF,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;EACH,wBAAwB,KAAK;EAC7B,wBAAwB,MAAM;EAC9B,wBAAwB,MAAM;CAClC;AACJ"}
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":";wBASgB,gBAAgB,+BAAuC"}
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 "./internals/plugins.js";
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 betteTailwindcss from "eslint-plugin-better-tailwindcss";
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": betteTailwindcss,
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 betteTailwindcss from 'eslint-plugin-better-tailwindcss';\n// @ts-expect-error No declare file.\nimport promise from 'eslint-plugin-promise';\n\nimport { createBaseRules } from './base';\nimport { customPlugins } from './internals/plugins';\n\nexport function createVueConfig(environment: 'bun' | 'node' = 'node'): TypedFlatConfigItem {\n return {\n files: ['**/*.vue'],\n plugins: {\n '@kikiutils/vue': kikiutilsEslintPluginVue,\n 'better-tailwindcss': betteTailwindcss,\n 'kikiutils': customPlugins,\n promise,\n },\n rules: {\n ...createBaseRules(environment),\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 '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/prefer-separate-static-class': 'error',\n 'vue/require-explicit-emits': 'error',\n 'vue/require-typed-ref': 'error',\n },\n };\n}\n"],"mappings":";;;;;;AASA,SAAgB,gBAAgB,cAA8B,QAA6B;CACvF,OAAO;EACH,OAAO,CAAC,UAAU;EAClB,SAAS;GACL,kBAAkB;GAClB,sBAAsB;GACtB,aAAa;GACb;EACJ;EACA,OAAO;GACH,GAAG,gBAAgB,WAAW;GAC9B,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,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,oCAAoC;GACpC,8BAA8B;GAC9B,yBAAyB;EAC7B;CACJ;AACJ"}
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": "9.3.1",
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
- "./internals/plugins": {
16
- "types": null,
17
- "import": null,
18
- "require": null
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
- "eslint-plugin-better-tailwindcss": "^4.10.0",
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-plugin-promise": "^7.3.0"
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
- "@kikiutils/eslint-config": "^9.3.0",
65
+ "@arethetypeswrong/core": "^0.18.5",
115
66
  "@kikiutils/tsconfigs": "^7.0.0",
116
- "@types/node": "^26.6.5",
67
+ "@types/node": "^26.6.6",
117
68
  "@vitest/coverage-v8": "^5.0.5",
118
69
  "changelogen": "^0.6.2",
119
- "eslint": "^10.13.0",
120
- "eslint-plugin-better-tailwindcss": "^4.10.0",
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.2",
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 closingLine = sourceCode.lines[lastToken.loc.end.line - 1]!;
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 (!hasDifferentIndent && !hasStandaloneClosing && !hasBlockClosing) continue;
40
- const comments = sourceCode.getCommentsBefore(next);
41
- if (
42
- sourceCode
43
- .lines
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
- // Keep leading comments attached to the next statement and trailing comments in place.
51
- const boundary = comments
52
- .find((comment) => comment.loc!.start.line > lastToken.loc.end.line) ?? firstToken;
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
- const offset = boundary.loc!.start.line > lastToken.loc.end.line
55
- ? boundary.range![0] - boundary.loc!.start.column
56
- : boundary.range![0];
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
- boundary.loc!.start.line === lastToken.loc.end.line ? '\n\n' : '\n',
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 after closing lines, blocks, or indentation changes.' },
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
+ }