import type { AST , Rule } from 'eslint' ; import type { AttributeToken , Loc , TagToken , TextToken } from 'pug-lexer' ; import type { TokenProcessorContext } from '../utils' ; import { processRule } from '../utils' ; import { previousTagToken } from '../utils/pug-utils' ; import { isVueBinding } from '../utils/vue' ; export default { meta : { type : 'suggestion' , docs : { description : 'disallow usage of `this` in template' , categories : [ 'vue3-recommended' , 'recommended' ] , url : 'https://eslint.vuejs.org/rules/this-in-template.html' } , fixable : 'code' , schema : [ { enum : [ 'always' , 'never' ] } ] } , create ( context ) { return processRule ( context , ( ) => { const option = context . options [ 0 ] !== 'always' ? 'never' : 'always' ; function handle ( token , { index , tokens } ) { if ( typeof token . val === 'string' && ( token . type === 'text' || isVueBinding ( token ) ) && /this\??\.(?!class)/ . test ( token . val ) ) { if ( option === 'never' ) { const lastTagToken = previousTagToken ( tokens , index ) ; if ( lastTagToken ) { const lastTagTokenIndex = tokens . indexOf ( lastTagToken ) ; const vForAttributeToken = tokens . slice ( lastTagTokenIndex , index ) . find ( ( t ) => t . type === 'attribute' && t . name === 'v-for' ) as AttributeToken | undefined ; if ( typeof vForAttributeToken ?. val === 'string' ) { const ofLoopVariableName = vForAttributeToken . val . slice ( 1 , - 1 ) . trim ( ) . split ( ' of' ) [ 0 ] ?. trim ( ) ?? '' ; if ( token . val . includes ( `this.${ ofLoopVariableName }` ) ) { return ; } } } const withOptionalChaining = token . val . includes ( 'this?.' ) ; const loc = token . loc ; const range = token . range ; const textSlice = context . getSourceCode ( ) . text . slice ( range [ 0 ] , range [ 1 ] ) ; const columnOffset = textSlice . indexOf ( `this${ withOptionalChaining ? '?' : '' }.` ) ; const columnStart = loc . start . column - 1 + columnOffset ; const columnEnd = columnStart + 'this' . length + ( withOptionalChaining ? 1 : 0 ) ; context . report ( { node : { type : 'ThisExpression' } , loc : { line : loc . start . line , column : loc . start . column - 1 , start : { line : loc . start . line , column : columnStart } , end : { line : loc . end . line , column : columnEnd } } , fix ( fixer ) { const removeFrom = range [ 0 ] + columnOffset ; const removeTo = removeFrom + 'this.' . length + ( withOptionalChaining ? 1 : 0 ) ; return fixer . removeRange ( [ removeFrom , removeTo ] ) ; } , message : "Unexpected usage of 'this'." } ) ; } else { } } } return { attribute : handle , text : handle } ; } ) ; } } as Rule . RuleModule ;