import type { Rule } from 'eslint' ; import type { Loc } from 'pug-lexer' ; import { processRule } from '../utils' ; export default { meta : { type : 'problem' , docs : { description : 'disallow duplication of attributes' , categories : [ 'vue3-essential' , 'essential' ] , url : 'https://eslint.vuejs.org/rules/no-duplicate-attributes.html' } , fixable : undefined , schema : [ { type : 'object' , properties : { allowCoexistClass : { type : 'boolean' } , allowCoexistStyle : { type : 'boolean' } } , additionalProperties : false } ] } , create ( context ) { return processRule ( context , ( ) => { const { allowCoexistStyle = true , allowCoexistClass = true } = context . options [ 0 ] ?? { } ; let currentAttributeNames = [ ] ; function findDuplicate ( name ) { if ( allowCoexistClass && /^(v-bind)?:?class$/i . test ( name ) ) { return ; } if ( allowCoexistStyle && /^(v-bind)?:?style$/i . test ( name ) ) { return ; } return currentAttributeNames . find ( ( attrName ) => attrName === name ) ; } return { 'start-attributes' ( ) { currentAttributeNames = [ ] ; } , attribute ( token ) { const attributeName = token . name ; if ( /^(@|v-on:)/ . test ( attributeName ) ) { return ; } const cleanedAttributeName = attributeName . replace ( /^(v-bind)?:/ , '' ) ; const duplicateAttributeName = findDuplicate ( cleanedAttributeName ) ; if ( duplicateAttributeName ) { const loc = token . loc ; const columnStart = loc . start . column - 1 ; const columnEnd = columnStart + attributeName . length ; context . report ( { node : { } as unknown as Rule . Node , loc : { line : loc . start . line , column : loc . start . column - 1 , start : { line : loc . start . line , column : columnStart } , end : { line : loc . end . line , column : columnEnd } } , message : "Duplicate attribute '{{name}}'." , data : { name : duplicateAttributeName } } ) ; } currentAttributeNames . push ( cleanedAttributeName ) ; } } ; } ) ; } } as Rule . RuleModule ;