vue.ts 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. import type { Linter } from 'eslint';
  2. import { interopDefault } from '../util';
  3. export async function vue(): Promise<Linter.Config[]> {
  4. const [pluginVue, parserVue, parserTs] = await Promise.all([
  5. interopDefault(import('eslint-plugin-vue')),
  6. interopDefault(import('vue-eslint-parser')),
  7. // @ts-expect-error missing types
  8. interopDefault(import('@typescript-eslint/parser')),
  9. ] as const);
  10. const flatEssential = pluginVue.configs?.['flat/essential'] || [];
  11. const flatStronglyRecommended =
  12. pluginVue.configs?.['flat/strongly-recommended'] || [];
  13. const flatRecommended = pluginVue.configs?.['flat/recommended'] || [];
  14. return [
  15. ...flatEssential,
  16. ...flatStronglyRecommended,
  17. ...flatRecommended,
  18. {
  19. files: ['**/*.vue'],
  20. languageOptions: {
  21. // globals: {
  22. // computed: 'readonly',
  23. // defineEmits: 'readonly',
  24. // defineExpose: 'readonly',
  25. // defineProps: 'readonly',
  26. // onMounted: 'readonly',
  27. // onUnmounted: 'readonly',
  28. // reactive: 'readonly',
  29. // ref: 'readonly',
  30. // shallowReactive: 'readonly',
  31. // shallowRef: 'readonly',
  32. // toRef: 'readonly',
  33. // toRefs: 'readonly',
  34. // watch: 'readonly',
  35. // watchEffect: 'readonly',
  36. // },
  37. parser: parserVue,
  38. parserOptions: {
  39. ecmaFeatures: {
  40. jsx: true,
  41. },
  42. extraFileExtensions: ['.vue'],
  43. parser: parserTs,
  44. sourceType: 'module',
  45. },
  46. },
  47. plugins: {
  48. vue: pluginVue,
  49. },
  50. processor: pluginVue.processors?.['.vue'],
  51. rules: {
  52. ...pluginVue.configs?.base?.rules,
  53. 'vue/attribute-hyphenation': [
  54. 'error',
  55. 'always',
  56. {
  57. ignore: [],
  58. },
  59. ],
  60. 'vue/attributes-order': 'off',
  61. 'vue/block-order': [
  62. 'error',
  63. {
  64. order: ['script', 'template', 'style'],
  65. },
  66. ],
  67. 'vue/component-name-in-template-casing': ['error', 'PascalCase'],
  68. 'vue/component-options-name-casing': ['error', 'PascalCase'],
  69. 'vue/custom-event-name-casing': ['error', 'camelCase'],
  70. 'vue/define-macros-order': [
  71. 'error',
  72. {
  73. order: [
  74. 'defineOptions',
  75. 'defineProps',
  76. 'defineEmits',
  77. 'defineSlots',
  78. ],
  79. },
  80. ],
  81. 'vue/dot-location': ['error', 'property'],
  82. 'vue/dot-notation': ['error', { allowKeywords: true }],
  83. 'vue/eqeqeq': ['error', 'smart'],
  84. 'vue/html-closing-bracket-newline': 'error',
  85. 'vue/html-indent': 'off',
  86. // 'vue/html-indent': ['error', 2],
  87. 'vue/html-quotes': ['error', 'double'],
  88. 'vue/html-self-closing': [
  89. 'error',
  90. {
  91. html: {
  92. component: 'always',
  93. normal: 'never',
  94. void: 'always',
  95. },
  96. math: 'always',
  97. svg: 'always',
  98. },
  99. ],
  100. 'vue/max-attributes-per-line': 'off',
  101. 'vue/multi-word-component-names': 'off',
  102. 'vue/multiline-html-element-content-newline': 'error',
  103. 'vue/no-empty-pattern': 'error',
  104. 'vue/no-extra-parens': ['error', 'functions'],
  105. 'vue/no-irregular-whitespace': 'error',
  106. 'vue/no-loss-of-precision': 'error',
  107. 'vue/no-reserved-component-names': 'off',
  108. 'vue/no-restricted-syntax': [
  109. 'error',
  110. 'DebuggerStatement',
  111. 'LabeledStatement',
  112. 'WithStatement',
  113. ],
  114. 'vue/no-restricted-v-bind': ['error', '/^v-/'],
  115. 'vue/no-sparse-arrays': 'error',
  116. 'vue/no-unused-refs': 'error',
  117. 'vue/no-useless-v-bind': 'error',
  118. 'vue/object-shorthand': [
  119. 'error',
  120. 'always',
  121. {
  122. avoidQuotes: true,
  123. ignoreConstructors: false,
  124. },
  125. ],
  126. 'vue/one-component-per-file': 'error',
  127. 'vue/prefer-import-from-vue': 'error',
  128. 'vue/prefer-separate-static-class': 'error',
  129. 'vue/prefer-template': 'error',
  130. 'vue/prop-name-casing': ['error', 'camelCase'],
  131. 'vue/require-default-prop': 'error',
  132. 'vue/require-explicit-emits': 'error',
  133. 'vue/require-prop-types': 'off',
  134. 'vue/singleline-html-element-content-newline': 'off',
  135. 'vue/space-infix-ops': 'error',
  136. 'vue/space-unary-ops': ['error', { nonwords: false, words: true }],
  137. 'vue/v-on-event-hyphenation': [
  138. 'error',
  139. 'always',
  140. {
  141. autofix: true,
  142. ignore: [],
  143. },
  144. ],
  145. },
  146. },
  147. ];
  148. }