Eslint-plugin-vue: Some rules are not working while using vue-class-component

Created on 7 Dec 2019  Â·  4Comments  Â·  Source: vuejs/eslint-plugin-vue

My environment

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.

class-component typescript

Most helpful comment

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.

All 4 comments

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.

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 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)

@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.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Mouvedia picture Mouvedia  Â·  3Comments

nirazul picture nirazul  Â·  3Comments

KristofMorva picture KristofMorva  Â·  4Comments

rodneyrehm picture rodneyrehm  Â·  4Comments

prograhammer picture prograhammer  Â·  3Comments