44import type { Rule } from 'eslint' ;
55import { createVisitors } from '@html-eslint/eslint-plugin/lib/rules/utils/visitors.js' ;
66import { findAttr } from '@html-eslint/eslint-plugin/lib/rules/utils/node.js' ;
7- import type { HtmlTagNode } from '../rule-types.js' ;
7+ import type { HtmlAttribute , HtmlTagNode } from '../rule-types.js' ;
88
99declare const __ELEMENTS_PAGES_BASE_URL__ : string ;
10- const DEPRECATED_ATTRIBUTES = {
10+
11+ interface DeprecatedAttributeConfig {
12+ replacement ?: string ;
13+ values ?: string [ ] ;
14+ }
15+
16+ interface DeprecatedAttributeReport {
17+ attr : HtmlAttribute ;
18+ attribute : string ;
19+ config : DeprecatedAttributeConfig ;
20+ }
21+
22+ const DEPRECATED_ATTRIBUTES : Record < string , Record < string , DeprecatedAttributeConfig > > = {
1123 'nve-badge' : {
12- status : [ 'trend-up' , 'trend-down' , 'trend-neutral' ]
24+ status : { values : [ 'trend-up' , 'trend-down' , 'trend-neutral' ] }
25+ } ,
26+ 'nve-combobox' : {
27+ notags : { replacement : 'tag-layout="hidden"' }
1328 }
1429} ;
1530
31+ function attributeValueIsDeprecated ( config : DeprecatedAttributeConfig , value ?: string ) {
32+ return ! config . values || ( ! ! value && config . values . includes ( value ) ) ;
33+ }
34+
35+ function reportDeprecatedAttribute ( context : Rule . RuleContext , { attr, attribute, config } : DeprecatedAttributeReport ) {
36+ const replacement = config . replacement ;
37+ const messageId = config . replacement
38+ ? 'unexpected-deprecated-attribute-replacement'
39+ : 'unexpected-deprecated-attribute' ;
40+ const report : Rule . ReportDescriptor = {
41+ node : attr ,
42+ data : {
43+ attribute,
44+ replacement : config . replacement ?? '' ,
45+ value : attr . value ?. value ?? ''
46+ } ,
47+ messageId
48+ } ;
49+ if ( replacement ) {
50+ report . fix = fixer => fixer . replaceText ( attr , replacement ) ;
51+ }
52+ context . report ( report ) ;
53+ }
54+
1655const rule = {
1756 meta : {
1857 type : 'problem' as const ,
58+ fixable : 'code' as const ,
1959 docs : {
2060 description : 'Disallow use of deprecated attributes in HTML.' ,
2161 category : 'Best Practice' ,
@@ -24,27 +64,22 @@ const rule = {
2464 } ,
2565 schema : [ ] ,
2666 messages : {
27- [ 'unexpected-deprecated-attribute' ] : 'Unexpected use of deprecated value "{{value}}" in attribute "{{attribute}}"'
67+ [ 'unexpected-deprecated-attribute' ] :
68+ 'Unexpected use of deprecated value "{{value}}" in attribute "{{attribute}}"' ,
69+ [ 'unexpected-deprecated-attribute-replacement' ] :
70+ 'Unexpected use of deprecated attribute "{{attribute}}". Use {{replacement}} instead.'
2871 }
2972 } ,
3073 create ( context : Rule . RuleContext ) {
3174 return createVisitors ( context , {
3275 Tag ( node : HtmlTagNode ) {
33- const deprecatedAttributes : Record < string , string [ ] > | undefined =
76+ const deprecatedAttributes : Record < string , DeprecatedAttributeConfig > | undefined =
3477 DEPRECATED_ATTRIBUTES [ node . name as keyof typeof DEPRECATED_ATTRIBUTES ] ;
3578 if ( deprecatedAttributes ) {
36- Object . entries ( deprecatedAttributes ) . forEach ( ( [ attribute , values ] ) => {
79+ Object . entries ( deprecatedAttributes ) . forEach ( ( [ attribute , config ] ) => {
3780 const attr = findAttr ( node , attribute ) ;
38- const value = attr ?. value ?. value ;
39- if ( attr && values . includes ( value ) ) {
40- context . report ( {
41- node : attr ,
42- data : {
43- attribute,
44- value
45- } ,
46- messageId : 'unexpected-deprecated-attribute'
47- } ) ;
81+ if ( attr && attributeValueIsDeprecated ( config , attr . value ?. value ) ) {
82+ reportDeprecatedAttribute ( context , { attr, attribute, config } ) ;
4883 }
4984 } ) ;
5085 }
0 commit comments