Repository: vuejs/eslint-plugin-vue (JavaScript)

Issue:
Add support for `defineOptions` to `vue/no-duplicate-attr-inheritance`
<!--
  ❗Please don't ignore this template.❗

  If you ignore it, we're just going to respond asking you to fill it out, which wastes everyone's time.
  The more relevant information you can include, the faster we can find the issue and fix it without asking you for more info.
-->

<!--
  Before posting the issue, please confirm that the problem you're getting
  is not related to your code editor configuration.
  To make sure it's not, run: yarn eslint src/your-file.vue
-->

**Checklist**

- [x] I have tried restarting my IDE and the issue persists.
- [x] I have read the [FAQ](https://eslint.vuejs.org/user-guide/#faq) and my problem is not listed.
<!-- If you do not read the FAQ and open an issue that is listed in the FAQ, we may silently close the issue. -->

**Tell us about your environment**

- **ESLint version:^8.13.0** 
- **eslint-plugin-vue version:NA** 
- **Node version:LTS** 
- **Operating System:Windows** 

**Please show your full configuration:**
<!-- Paste content of your .eslintrc file -->
```json5
module.exports = {
  env: {
    browser: true,
    es2021: true,
  },
  extends: [
    '@antfu',
    'plugin:vue/vue3-recommended',
    'plugin:import/recommended',
    'plugin:import/typescript',
    'plugin:promise/recommended',
    'plugin:sonarjs/recommended',
  ],
  parserOptions: {
    ecmaVersion: 13,
    parser: '@typescript-eslint/parser',
    sourceType: 'module',
  },
  plugins: ['vue', '@typescript-eslint'],
  rules: {
    'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
    'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',

    // Disable max-len
    'max-len': 'off',

    // we don't want it
    semi: ['error', 'never'],

    // add parens ony when required in arrow function
    'arrow-parens': ['error', 'as-needed'],

    // add new line above comment
    'newline-before-return': 'error',

    // add new line above comment
    'lines-around-comment': [
      'error',
      {
        beforeBlockComment: true,
        beforeLineComment: true,
        allowBlockStart: true,
        allowClassStart: true,
        allowObjectStart: true,
        allowArrayStart: true,
      },
    ],

    'array-element-newline': ['error', 'consistent'],
    'array-bracket-newline': ['error', 'consistent'],

    'vue/multi-word-component-names': 'off',

    // Plugin: eslint-plugin-import
    'import/prefer-default-export': 'off',

    // Plugin: eslint-plugin-import
    // For omitting extension for ts files
    'import/extensions': [
      'error',
      'ignorePackages',
      {
        js: 'never',
        jsx: 'never',
        ts: 'never',
        tsx: 'never',
      },
    ],

    // Thanks: https://stackoverflow.com/a/63961972/10796681
    'no-shadow': 'off',
    '@typescript-eslint/no-shadow': ['error'],

    '@typescript-eslint/consistent-type-imports': 'error',

    // Plugin: eslint-plugin-promise
    'promise/always-return': 'off',
    'promise/catch-or-return': 'off',

    // ESLint plugin vue
    'vue/block-tag-newline': 'error',
    'vue/component-api-style': 'error',
    'vue/component-name-in-template-casing': 'error',
    'vue/custom-event-name-casing': 'error',
    'vue/define-macros-order': 'error',
    'vue/html-comment-content-newline': 'error',
    'vue/html-comment-content-spacing': 'error',
    'vue/html-comment-indent': 'error',
    'vue/match-component-file-name': 'error',
    'vue/no-child-content': 'error',
    'vue/no-duplicate-attr-inheritance': 'error',
    'vue/no-empty-component-block': 'error',
    'vue/no-multiple-objects-in-class': 'error',
    'vue/no-reserved-component-names': 'error',
    'vue/no-template-target-blank': 'error',
    'vue/no-useless-mustaches': 'error',
    'vue/no-useless-v-bind': 'error',
    'vue/padding-line-between-blocks': 'error',
    'vue/prefer-separate-static-class': 'error',
    'vue/prefer-true-attribute-shorthand': 'error',
    'vue/v-on-function-call': 'error',

    // -- Extension Rules
    'vue/no-irregular-whitespace': 'error',
    'vue/template-curly-spacing': 'error',

    // Internal Rules
    'valid-appcardcode-code-prop': 'error',
  },
  settings: {
    // 'import/parsers': {
    //   '@typescript-eslint/parser': ['.ts', '.tsx'],
    // },
    'import/resolver': {
      typescript: {
        // alwaysTryTypes: true,
        // project: './tsconfig.json',
      },
    },
  },
}

```

**What did you do?**	
<!-- Please include the actual source code causing the issue. -->
```vue
 <v-card v-bind="$attrs">
...
 </v-card>

<script setup lang="ts">
// inherit Attribute make false
defineOptions({
  inheritAttrs: false,
})
</script>
```

**What did you expect to happen?**
Error should gone.

**What actually happened?**
<!--
  Please include the actual, raw output from ESLint.
  If you are only looking at your editor extension results, check the CLI results.
-->
Set "inheritAttrs" to false.eslint[vue/no-duplicate-attr-inheritance](https://eslint.vuejs.org/rules/no-duplicate-attr-inheritance.html)

**Repository to reproduce this issue**
<!--
  ❗ Please share a repository that can reproduce your issue.
  ❗ If you don't share it, we just label it as requesting a repository that can reproduce your issue.
  ❗ If you don't share it for a few days, we silently close this issue.
-->

I have used the `unplugin-vue-define-options` plugin for the above declaration.



Discussion:
`defineOptions` is currently only suggested in an RFC, so it's not officially supported by eslint-plugin-vue. Users of the unplugin should disable that rule.
defineOptions is now a thing, and it seems this error is still thrown.
Seems like we missed this in #2118/#2127. Thanks for letting us know! I'll reopen this.
I didn't know we could use `$attrs` with `<script setup>`. We probably have the same problem with `<script>export default {inheritAttrs: false}</script>` with `<script setup>`.



Patch:
diff --git a/lib/rules/no-duplicate-attr-inheritance.js b/lib/rules/no-duplicate-attr-inheritance.js
index eea2bf765..a8661b091 100644
--- a/lib/rules/no-duplicate-attr-inheritance.js
+++ b/lib/rules/no-duplicate-attr-inheritance.js
@@ -26,12 +26,23 @@ module.exports = {
     /** @type {string | number | boolean | RegExp | BigInt | null} */
     let inheritsAttrs = true
 
-    return Object.assign(
-      utils.executeOnVue(context, (node) => {
-        const inheritAttrsProp = utils.findProperty(node, 'inheritAttrs')
+    /** @param {ObjectExpression} node */
+    function processOptions(node) {
+      const inheritAttrsProp = utils.findProperty(node, 'inheritAttrs')
 
-        if (inheritAttrsProp && inheritAttrsProp.value.type === 'Literal') {
-          inheritsAttrs = inheritAttrsProp.value.value
+      if (inheritAttrsProp && inheritAttrsProp.value.type === 'Literal') {
+        inheritsAttrs = inheritAttrsProp.value.value
+      }
+    }
+
+    return utils.compositingVisitors(
+      utils.executeOnVue(context, processOptions),
+      utils.defineScriptSetupVisitor(context, {
+        onDefineOptionsEnter(node) {
+          if (node.arguments.length === 0) return
+          const define = node.arguments[0]
+          if (define.type !== 'ObjectExpression') return
+          processOptions(define)
         }
       }),
       utils.defineTemplateBodyVisitor(context, {


Test patch:
diff --git a/tests/lib/rules/no-duplicate-attr-inheritance.js b/tests/lib/rules/no-duplicate-attr-inheritance.js
index b4a00c228..7fc112123 100644
--- a/tests/lib/rules/no-duplicate-attr-inheritance.js
+++ b/tests/lib/rules/no-duplicate-attr-inheritance.js
@@ -79,6 +79,26 @@ ruleTester.run('no-duplicate-attr-inheritance', rule, {
         export default {  }
         </script>
       `
+    },
+    {
+      filename: 'test.vue',
+      code: `
+      <script>
+      export default { inheritAttrs: false }
+      </script>
+      <script setup>
+      </script>
+      <template><div v-bind="$attrs" /></template>
+      `
+    },
+    {
+      filename: 'test.vue',
+      code: `
+      <script setup>
+      defineOptions({ inheritAttrs: false })
+      </script>
+      <template><div v-bind="$attrs" /></template>
+      `
     }
   ],
 
@@ -99,6 +119,38 @@ ruleTester.run('no-duplicate-attr-inheritance', rule, {
         </script>
       `,
       errors: ['Set "inheritAttrs" to false.']
+    },
+    {
+      filename: 'test.vue',
+      code: `
+      <script>
+      export default { inheritAttrs: true }
+      </script>
+      <script setup>
+      </script>
+      <template><div v-bind="$attrs" /></template>
+      `,
+      errors: [
+        {
+          message: 'Set "inheritAttrs" to false.',
+          line: 7
+        }
+      ]
+    },
+    {
+      filename: 'test.vue',
+      code: `
+      <script setup>
+      defineOptions({ inheritAttrs: true })
+      </script>
+      <template><div v-bind="$attrs" /></template>
+      `,
+      errors: [
+        {
+          message: 'Set "inheritAttrs" to false.',
+          line: 5
+        }
+      ]
     }
   ]
 })