vuejs / eslint-plugin-vue

Official ESLint plugin for Vue.js
https://eslint.vuejs.org/
MIT License
4.47k stars 667 forks source link

vue/no-undef-properties in v9.30 still emits error for Vuex mutation or getter #2600

Open tmcdos opened 2 weeks ago

tmcdos commented 2 weeks ago

Checklist

Tell us about your environment

Please show your full configuration:

// https://eslint.org/docs/user-guide/configuring
const path = require('path');

module.exports = {
  root: true,
  parserOptions: {
    parser: '@babel/eslint-parser',
    ecmaVersion: 2020,
    requireConfigFile: false,
    babelOptions:
    {
      configFile: path.resolve(__dirname, './babel.config.js')
    }
  },
  env:
  {
    browser: true,
    node: true,
  },
  extends: [
    // https://github.com/vuejs/eslint-plugin-vue#priority-a-essential-error-prevention
    // consider switching to `plugin:vue/strongly-recommended` or `plugin:vue/recommended` for stricter rules.
    'plugin:vue/recommended',
    // https://github.com/standard/standard/blob/master/docs/RULES-en.md
    '@vue/eslint-config-standard',
  ],
  // add your custom rules here
  rules: {
    // allow async-await
    'generator-star-spacing': 'off',
    semi: ['error', 'always'],
    'brace-style': ['error', 'allman'],
    'space-before-function-paren': ['error', {
      anonymous: 'never',
      named: 'never',
      asyncArrow: 'always'
    }],
    'object-curly-newline': [
      'error',
      {
        ObjectExpression: {
          multiline: true,
          minProperties: 2,
          consistent: true
        },
        ObjectPattern: { multiline: true },
        ImportDeclaration: { multiline: true },
        ExportDeclaration: {
          multiline: true,
          minProperties: 3
        }
      }
    ],
    'object-property-newline': [
      'error',
      { allowAllPropertiesOnSameLine: false }
    ],
    'comma-dangle': [
      'error',
      {
        arrays: 'only-multiline',
        objects: 'only-multiline',
        imports: 'never',
        exports: 'never',
        functions: 'never'
      }
    ],
    quotes: [
      'error',
      'single',
      {
        avoidEscape: true,
        allowTemplateLiterals: true
      }
    ],
    'one-var': [
      'error',
      {
        uninitialized: 'always',
        initialized: 'never'
      }
    ],

    'block-scoped-var': "error",
    'default-param-last': ["error"],
    'func-names': ["error", "as-needed"],
    'func-style': ["error", "declaration", { "allowArrowFunctions": true }],
    'max-statements-per-line': ["error", { "max": 1 }],
    'no-confusing-arrow': "error",
    'no-constant-binary-expression': "error",
    'no-dupe-else-if': "error",
    'no-lonely-if': "error",
    'no-loop-func': "error",
    'nonblock-statement-body-position': ["error", "beside"],
    'no-negated-in-lhs': "error",
    'no-shadow': "error",
    'no-spaced-func': "error",
    'no-unsafe-optional-chaining': ["error", { "disallowArithmeticOperators": true }],
    'no-useless-concat': "error",
    'semi-style': ["error", "last"],
    'vars-on-top': "error",

    'vue/no-undef-properties': 'error',
  }
}

What did you do?

import Vue from 'vue';
import App from './App.vue';
import store from './store/store';
import { mapGetters, mapMutations } from 'vuex';

new Vue({
  name: 'RootVue',
  computed:
  {
    ...mapGetters(['getCountryMap']),
  },
  watch:
  {
    getCountryMap()
    {
      this.updatePrefix();
    },
  },
  created()
  {
    this.setCountries([]);
  },
  methods:
  {
    ...mapMutations(['setCountries']),
    updatePrefix()
    {
      //
    },
  },
  store,
  render: h => h(App)
}).$mount('#app');

What did you expect to happen? I expect no linting error of type vue/no-undef-properties to be reported for lines 14:5 and 21:10

What actually happened?

You may use special comments to disable some warnings.
Use // eslint-disable-next-line to ignore the next line.
Use /* eslint-disable */ to ignore all warnings in a file.
ERROR in [eslint]
Z:\_\src\main.js
  14:5   error  'getCountryMap' is not defined  vue/no-undef-properties
  21:10  error  'setCountries' is not defined   vue/no-undef-properties

✖ 2 problems (2 errors, 0 warnings)

webpack compiled with 1 error

shot-1

Repository to reproduce this issue

https://codesandbox.io/p/devbox/gallant-swirles-ljp5n5

shot-2

FloEdelmann commented 2 weeks ago

Additional context from https://github.com/vuejs/eslint-plugin-vue/pull/2513#issuecomment-2459347922:

There is a problem with this fix - it works only if mapGetters or mapState or mapMutations appears in the source code BEFORE the actual reference to the property or method. For example, in the following code no linting error will be emitted

  created()
  {
    if (this.getCountries.length === 0) this.fetchCountries();
  },
methods:
{
        ...mapMutations(['setCountries']),
      fetchCountries()
      {
          // ... fetching from server
          this.setCountries(data);
      }
}

However, in the following code a linting error setCountries is not defined vue/no-undef-properties will be emitted

  created()
  {
    if (this.getCountries.length === 0)
    {
          // ... fetching from server
          this.setCountries(data); // <==== linting error - but it should not be
    }
  },
methods:
{
        ...mapMutations(['setCountries']),
}
tmcdos commented 2 weeks ago

Another problem is that the fix for Vuex/Pinia in vue/no-undef-properties rule only recognizes string literals - but ignores constants. So for example code like this will fail with a linting error:

import { mapGetters } from 'vuex';

const GET_SOMETHING = 'GET_SOMETHING';

export default
{
    computed:
    {
       ...mapGetters([GET_SOMETHING]),
    },
  methods:
  {
     someFunction()
    {
        if (this[GET_SOMETHING]) // <===== here will be a linting error "vue/no-undef-properties"
        {
           // .... some code
        }
    }
  }
}