eslint-plugin-vue icon indicating copy to clipboard operation
eslint-plugin-vue copied to clipboard

Some rules are not working while using vue-class-component

Open horrylala opened this issue 6 years ago • 7 comments

My environment

  • ESLint version:6.7.1
  • eslint-plugin-vue version:6.0.1
  • Node version:v11.14.0

Please show your full configuration:

module.exports = {
  root: true,
  env: {
    node: true,
  },
  extends: [
    // airbnb
    'airbnb-base',
    // vue lint
    // https://github.com/vuejs/eslint-plugin-vue#priority-a-essential-error-prevention
    'plugin:vue/recommended',
    // https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/eslint-plugin
    'plugin:@typescript-eslint/recommended',
    // prettier
    'prettier',
    'prettier/@typescript-eslint',
    'prettier/vue',
    '@vue/typescript'
  ],
  plugins: [
    // 'html'
  ],
  rules: {
    // ... 
    'no-multiple-empty-lines': ["error", { "max": 1 }],
    // ===
    'eqeqeq': ["error", "always"],
    // max-len: 180
    'max-len': ['error', 180],
    // todo: vue/order-in-components, not working
    // todo: vue/prop-name-casing , not working,
    // todo: vue/no-async-in-computed-properties , not working
    // todo: vue/no-duplicate-attributes ,not working
    'vue/no-dupe-keys': ['error'], // still not working 
    /*--------------------- vue rules ---------------------*/
    // Vue component naming,PascalCase:'MyComponent ',kebab-case:'my-component'
    'vue/name-property-casing': ['error', 'PascalCase'],
    // vue template naming,PascalCase:<MyComponent></MyComponent>  kebab-case: '<my-component></my-component>'
		'vue/component-name-in-template-casing': ['error', 'kebab-case'],
    /*--------------------- ts rules ---------------------*/
		'@typescript-eslint/no-unused-vars': ['error'],
    // typescript-eslint
    '@typescript-eslint/interface-name-prefix': 'off',
    '@typescript-eslint/explicit-function-return-type': 'off',
  },
  parser: 'vue-eslint-parser',
  parserOptions: {
    'parser': '@typescript-eslint/parser',
    'project': 'tsconfig.json',
    'tsconfigRootDir': './',
    'extraFileExtensions': ['.vue']
  },
};

What did you do?

import { Vue } from "vue-property-decorator"

interface IState {
  arr: []
}
interface IProps {
  'prop-a': number
}

export default class Home extends Vue<IState, IProps> {
  // todo:eslint message: string = 'hello'
  message = 'hello'

  activated () {
    this.$el = 'nnn'
    console.log('actived')
  }

  onClick (): void {
    const message = 'dd'
    console.log(message)
    console.log(this.message)
    const longStr = 'str1234567…………189190191……str1………189190191……189190191……str1234567…………18919019str1234567…………189190191……str1234567…………189190191……str1234567…………189190191……1……'
    console.log(longStr)
  }

  get valA () {
    return Promise.all([new Promise((resolve) => {resolve('hhh')})])
  }
}

What did you expect to happen? It should show some errors.

What actually happened?

Nothing errors are shown.

More description I just import vue and typescript without using vue-cli. And i want using eslint-plugin-vue to lint my vue files which using vue-class-component.

horrylala avatar Dec 07 '19 10:12 horrylala

I have the same problem.

When I use a classic mono file vue.js without "vue-property-decorator", it works: image

But with "vue-property-decorator", it doesn't work. The linter says nothing: image

Regards.

frck006 avatar Dec 22 '19 14:12 frck006

Thank you for this issue.

Currently, this plugin does not support vue-class-component.

In order for this plugin to support vue-class-component, it is necessary to first identify the issues with each rule.

I want you to help with this task.

ota-meshi avatar Dec 26 '19 08:12 ota-meshi

@ota-meshi class-component and property-decorator is not only used for typescript (but mostly).

Main issue is with helper functions, there is no support for classes in them, getComponentProps is good example of function like this. https://github.com/vuejs/eslint-plugin-vue/blob/master/lib/utils/index.js#L430


in case of typescript + class some of rules are useless or they can be replaced by enforcing additional syntax on typescript, eg. if @Prop decorator is used we should require readonly property. this eliminates need for rules that checks if prop value is mutated, this is validated by typescript if prop is readonly.


examples of rules that should be used in typescript + class:

require-readonly-prop

module.exports = {
  meta: {
    fixable: 'code'
  },
  create (context) {
    function checkClassProperty (node) {
      const parent = node.parent
      if (parent.type === 'ClassProperty') {
        if (!parent.readonly) {
          context.report({
            message: '@Prop decorator should be readonly',
            node: parent.key,
            fix (fixer) {
              return fixer.insertTextBefore(parent.key, 'readonly ')
            }
          })
        }
      } else {
        context.report({
          message: '@Prop decorator can be present only on ClassProperty',
          node
        })
      }
    }

    return {
      "Decorator[expression.type='Identifier'][expression.name='Prop']" (node) {
        checkClassProperty(node)
      },
      "Decorator[expression.type='CallExpression'][expression.callee.type='Identifier'][expression.callee.name='Prop']" (node) {
        checkClassProperty(node)
      }
    }
  }
}
no-undefined-data

module.exports = {
  meta: {
    fixable: undefined,
    messages: {
      error: 'Component data must have value, otherwise it\'s not going to be reactive'
    }
  },
  create (context) {
    function isUndefined (node) {
      if (!node) {
        return true
      }
      return node.type === 'Identifier' && node.name === 'undefined'
    }

    function hasComponentDecorator (node) {
      if (!node || !node.decorators || !node.decorators.length) {
        return false
      }
      return node.decorators.some((el) => {
        return (
          el.type === 'Decorator' &&
          el.expression &&
          (
            (
              el.expression.type === 'Identifier' &&
              el.expression.name === 'Component'
            ) || (
              el.expression.type === 'CallExpression' &&
              el.expression.callee &&
              el.expression.callee.type === 'Identifier' &&
              el.expression.callee.name === 'Component'
            )
          )
        )
      })
    }

    return {
      'ClassDeclaration > ClassBody > ClassProperty' (node) {
        if (
          (!node.decorators || !node.decorators.length) &&
          hasComponentDecorator(node.parent.parent) &&
          isUndefined(node.value)
        ) {
          context.report({
            messageId: 'error',
            node
          })
        }
      }
    }
  }
}

note: this is just example and they may not support all cases (they require @Component decorator to be present on class level)

armano2 avatar Jan 03 '20 16:01 armano2

@ota-meshi "Currently, this plugin does not support vue-class-component." - Can you provide more information please? I do not know how this library performs the checks. Which rules(or in general) do not work for vue-class-component and why? I might look into helping fix this, but I am not sure where to start.

goldingdamien avatar Sep 17 '20 01:09 goldingdamien

Another rule doesn't work: match-component-file-name

Doc: https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/match-component-file-name.md Issue: https://github.com/vuejs/eslint-plugin-vue/issues/667

<script lang="ts">
// components/Normal.vue
import { Component, Vue } from 'vue-property-decorator';

// @vue/component
@Component
export default class Lol extends Vue {
    render(): null { return null; }
}
</script>

with the rule declared as

{
    'vue/match-component-file-name': ['error', {
      extensions: ['.vue', 'vue', 'vue.ts', 'jsx'],
      shouldMatchCase: true,
    }]
}

lgarczyn avatar Mar 23 '21 17:03 lgarczyn

This is still an issue, are there plans to fix it?

lgarczyn avatar Oct 27 '21 15:10 lgarczyn

Vue Class Component is no longer actively maintained and not recommended for Vue 3: https://class-component.vuejs.org/

This library is no longer actively maintained. It is no longer recommend to use Class-based components in Vue 3. The recommended way to use Vue 3 in large applications is Single-File Components, Composition API, and <script setup>.

So I suggest to not invest time in eslint-plugin-vue to start supporting this.

FloEdelmann avatar Dec 06 '23 16:12 FloEdelmann