Skip to content

Commit

Permalink
chore(web stack): add new ESLint Vue rules #5 (#7736)
Browse files Browse the repository at this point in the history
  • Loading branch information
ByScripts authored Jun 17, 2024
1 parent 070258d commit e1dd535
Show file tree
Hide file tree
Showing 13 changed files with 177 additions and 34 deletions.
78 changes: 59 additions & 19 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,16 +49,17 @@ module.exports = {
},
{
files: ['@xen-orchestra/{web-core,lite,web}/**/*.{vue,ts}'],
parser: 'vue-eslint-parser',
parserOptions: {
sourceType: 'module',
parser: '@typescript-eslint/parser',
},
plugins: ['import'],
extends: [
'plugin:import/recommended',
'plugin:import/typescript',
'plugin:vue/vue3-recommended',
'@vue/eslint-config-typescript/recommended',
'@vue/eslint-config-prettier',
'plugin:@typescript-eslint/recommended',
'plugin:vue/vue3-essential',
],
settings: {
'import/resolver': {
Expand All @@ -73,24 +74,76 @@ module.exports = {
},
},
},
globals: {
XO_LITE_VERSION: true,
XO_LITE_GIT_HEAD: true,
},
rules: {
'no-void': 'off',
'no-void': ['error', { allowAsStatement: true }],
'n/no-missing-import': 'off', // using 'import' plugin instead, to support TS aliases
'no-redeclare': 'off', // automatically checked by the TypeScript compiler
'no-dupe-class-members': 'off', // automatically checked by the TypeScript compiler
'@typescript-eslint/no-explicit-any': 'off',
'vue/require-default-prop': 'off', // https://github.com/vuejs/eslint-plugin-vue/issues/2051
'vue/multi-word-component-names': 'off',
// Vue 3 - Strongly Recommended
'vue/attribute-hyphenation': 'error',
'vue/component-definition-name-casing': 'error',
'vue/first-attribute-linebreak': 'error',
'vue/html-closing-bracket-newline': 'off', // Conflicts with Prettier
'vue/html-closing-bracket-spacing': 'error',
'vue/html-end-tags': 'error',
'vue/html-indent': 'off', // Conflicts with Prettier
'vue/html-quotes': 'error',
'vue/html-self-closing': ['error', { html: { void: 'always', normal: 'always', component: 'always' } }],
'vue/max-attributes-per-line': 'off', // Conflicts with Prettier
'vue/multiline-html-element-content-newline': 'error',
'vue/mustache-interpolation-spacing': 'error',
'vue/no-multi-spaces': 'error',
'vue/no-spaces-around-equal-signs-in-attribute': 'error',
'vue/no-template-shadow': 'error',
'vue/prop-name-casing': 'error',
'vue/require-default-prop': 'off', // https://github.com/vuejs/eslint-plugin-vue/issues/2051
'vue/require-explicit-emits': 'error',
'vue/require-prop-types': 'error',
'vue/singleline-html-element-content-newline': 'off',
'vue/v-bind-style': 'error',
'vue/v-on-event-hyphenation': ['error', 'always', { autofix: true }],
'vue/v-on-style': 'error',
'vue/v-slot-style': 'error',
// Vue 3 - Recommended
'vue/attributes-order': 'error',
'vue/no-lone-template': 'error',
'vue/no-multiple-slot-args': 'error',
'vue/no-v-html': 'error',
'vue/this-in-template': 'error',
// Vue 3 - Uncategorized
'vue/block-order': ['error', { order: ['template', 'script', 'style'] }],
'vue/block-tag-newline': ['error', { singleline: 'consistent', multiline: 'always', maxEmptyLines: 0 }],
'vue/component-api-style': ['error', ['script-setup']],
'vue/component-name-in-template-casing': ['error', 'PascalCase', { registeredComponentsOnly: false }],
'vue/custom-event-name-casing': ['error', 'camelCase'],
'vue/define-emits-declaration': ['error', 'type-literal'],
'vue/define-macros-order': [
'error',
{
order: ['defineOptions', 'defineProps', 'defineEmits', 'defineModel', 'defineSlots'],
defineExposeLast: true,
},
],
'vue/define-props-declaration': ['error', 'type-based'],
'vue/enforce-style-attribute': ['error', { allow: ['scoped', 'module'] }],
'vue/html-button-has-type': 'error',
'vue/html-comment-content-newline': ['error', { singleline: 'never', multiline: 'always' }],
'vue/html-comment-content-spacing': ['error', 'always'],
'vue/no-duplicate-attr-inheritance': 'error',
'vue/no-empty-component-block': 'error',
'vue/no-multiple-objects-in-class': 'error',
'vue/no-ref-object-reactivity-loss': 'error',
'vue/no-required-prop-with-default': 'error',
'vue/no-static-inline-styles': 'error',
'vue/no-template-target-blank': 'error',
'vue/no-undef-components': ['error', { ignorePatterns: ['RouterLink', 'RouterView', 'I18nT'] }],
'vue/no-undef-properties': 'error',
'vue/no-unused-refs': 'error',
'vue/no-use-v-else-with-v-for': 'error',
'vue/no-useless-mustaches': 'error',
Expand All @@ -101,20 +154,7 @@ module.exports = {
'vue/prefer-separate-static-class': 'error',
'vue/prefer-true-attribute-shorthand': 'error',
'vue/require-macro-variable-name': 'error',
'vue/html-button-has-type': 'error',
'vue/define-emits-declaration': ['error', 'type-literal'],
'vue/define-macros-order': [
'error',
{
order: ['defineOptions', 'defineProps', 'defineEmits', 'defineModel', 'defineSlots'],
defineExposeLast: true,
},
],
'vue/no-duplicate-attr-inheritance': 'error',
'vue/no-static-inline-styles': 'error',
'vue/no-template-target-blank': 'error',
'vue/component-name-in-template-casing': ['error', 'PascalCase', { registeredComponentsOnly: false }],
'vue/no-ref-object-reactivity-loss': 'error',
'vue/valid-define-options': 'error',
},
},
{
Expand Down
2 changes: 1 addition & 1 deletion @xen-orchestra/lite/src/components/AppLogin.vue
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
:readonly="isConnecting"
required
/>
<LoginError :error="error" />
<LoginError :error />
<label class="remember-me-label">
<FormCheckbox v-model="rememberMe" />
{{ $t('keep-me-logged') }}
Expand Down
2 changes: 1 addition & 1 deletion @xen-orchestra/lite/src/components/CodeHighlight.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<!-- eslint-disable vue/no-v-html -->
<pre class="code-highlight hljs"><code v-html="codeAsHtml"></code></pre>
<pre class="code-highlight hljs"><code v-html="codeAsHtml" /></pre>
<!-- eslint-enable vue/no-v-html -->
</template>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<tr>
<th>Event</th>
<th>Type</th>
<th></th>
<th />
</tr>
</thead>
<tbody>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<tr>
<th>Slot</th>
<th>Slots props</th>
<th></th>
<th />
</tr>
</thead>
<tbody>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<div class="form-widgets">
<FormWidget :label="$t('sort-by')">
<select v-model="newSortProperty">
<option v-if="!newSortProperty"></option>
<option v-if="!newSortProperty" />
<option v-for="(sort, property) in availableSorts" :key="property" :value="property">
{{ sort.label ?? property }}
</option>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<div :class="uiStore.isMobile ? 'mobile' : undefined" class="remote-console">
<div ref="consoleContainer" class="console"></div>
<div ref="consoleContainer" class="console" />
</div>
</template>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@
:key="index"
:color="segment.color"
:percentage="segment.percentage"
>
</StackedBarSegment>
/>
</div>
</template>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
</template>
<MenuItem
v-for="interaction in interactions"
v-tooltip="$t('core.coming-soon')"
:key="interaction.id"
v-tooltip="$t('core.coming-soon')"
:disabled="interaction.disabled"
:on-click="() => updateInteraction(interaction)"
>
Expand Down
2 changes: 2 additions & 0 deletions @xen-orchestra/web-core/lib/types/utility.type.ts
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
export type MaybeArray<T> = T | T[]

export type Noop = () => void
6 changes: 3 additions & 3 deletions @xen-orchestra/web-core/lib/utils/if-else.utils.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import type { MaybeArray } from '@core/types/utility.type'
import type { MaybeArray, Noop } from '@core/types/utility.type'
import { toArray } from '@core/utils/to-array.utils'
import { watch, type WatchOptions, type WatchSource } from 'vue'

export interface IfElseOptions extends Pick<WatchOptions, 'immediate'> {}

export function ifElse(
source: WatchSource<boolean>,
onTrue: MaybeArray<VoidFunction>,
onFalse: MaybeArray<VoidFunction>,
onTrue: MaybeArray<Noop>,
onFalse: MaybeArray<Noop>,
options?: IfElseOptions
) {
const onTrueFunctions = toArray(onTrue)
Expand Down
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
"@commitlint/cli": "^18.2.0",
"@commitlint/config-conventional": "^18.1.0",
"@limegrass/eslint-plugin-import-alias": "^1.1.0",
"@typescript-eslint/parser": "^7.12.0",
"@typescript-eslint/eslint-plugin": "^7.12.0",
"@vates/async-each": "^1.0.0",
"@vue/eslint-config-prettier": "^9.0.0",
"@vue/eslint-config-typescript": "^12.0.0",
Expand Down Expand Up @@ -40,7 +42,8 @@
"sorted-object": "^2.0.1",
"turbo": "^2.0.3",
"vue": "^2.7.14",
"vuepress": "^1.4.1"
"vuepress": "^1.4.1",
"vue-eslint-parser": "^9.4.3"
},
"engines": {
"node": ">=14",
Expand Down
Loading

0 comments on commit e1dd535

Please sign in to comment.