@@ -7,6 +7,7 @@ import { RuleCreator } from "@typescript-eslint/utils/eslint-utils";
77import { RuleContext as TSESLintRuleContext } from "@typescript-eslint/utils/ts-eslint" ;
88
99import urlCreator from "../url-creator" ;
10+ import { joiner } from "../utils/joiner" ;
1011import {
1112 parsePluginSettings ,
1213 PluginSettings ,
@@ -52,33 +53,6 @@ const isWhitelisted = (className: string, whitelist: Set<string>): boolean => {
5253 return [ ...whitelist ] . some ( ( pattern ) => passRegexTest ( pattern , className ) ) ;
5354} ;
5455
55- const removeClassname = (
56- invalidClassName : string ,
57- classNames : Array < string > ,
58- whitespaces : Array < string > ,
59- headSpace : boolean ,
60- tailSpace : boolean ,
61- ) => {
62- // Make a copy of whitespaces because we don't want to mutate the original array
63- // (Remember that ESLint runs several times and we don't want to mess up the whitespaces for the next runs)
64- const spaces = [ ...whitespaces ] ;
65-
66- const head = headSpace ? spaces . shift ( ) : "" ;
67- const tail = tailSpace ? spaces . pop ( ) : "" ;
68-
69- const validatedClasses : Array < string > = [ ] ;
70- for ( const [ index , className ] of classNames . entries ( ) ) {
71- if ( className !== invalidClassName ) {
72- const spacer =
73- validatedClasses . length === 0 ? "" : ( spaces [ index - 1 ] ?? " " ) ;
74- validatedClasses . push ( spacer + className ) ;
75- }
76- }
77-
78- if ( validatedClasses . length === 0 ) return "" ;
79- return head + validatedClasses . join ( "" ) + tail ;
80- } ;
81-
8256const detectCustomClassnames = (
8357 context : RuleContext ,
8458 settings : PluginSettings ,
@@ -99,25 +73,25 @@ const detectCustomClassnames = (
9973 // Process the extracted classnames and report
10074 const { classNames, whitespaces, headSpace, tailSpace } =
10175 getClassnamesFromValue ( originalClassNamesValue ) ;
102- for ( const cls of classNames ) {
103- if ( isWhitelisted ( cls , mergedWhitelist ) ) continue ;
104- if ( isValidClassNameWorker ( settings . cssConfigPath , cls ) ) continue ;
76+ for ( const customClass of classNames ) {
77+ if ( isWhitelisted ( customClass , mergedWhitelist ) ) continue ;
78+ if ( isValidClassNameWorker ( settings . cssConfigPath , customClass ) ) continue ;
10579
10680 // Generates the "cleaned" attribute value
107- let patchedValue = removeClassname (
108- cls ,
81+ let patchedValue = joiner ( {
10982 classNames,
11083 whitespaces,
11184 headSpace,
11285 tailSpace,
113- ) ;
86+ validator : ( candidate ) => candidate !== customClass ,
87+ } ) ;
11488 const patchedLoc = generateLocForClassname (
11589 node ,
116- cls ,
90+ customClass ,
11791 originalClassNamesValue ,
11892 genericContext ,
11993 ) ;
120- const range = getRange ( node , cls , originalClassNamesValue ) ;
94+ const range = getRange ( node , customClass , originalClassNamesValue ) ;
12195 patchedValue = prefix + patchedValue + suffix ;
12296
12397 if ( originalClassNamesValue === patchedValue ) {
@@ -127,15 +101,15 @@ const detectCustomClassnames = (
127101 loc : patchedLoc ,
128102 messageId : "issue:unknown-classname" ,
129103 data : {
130- classname : cls ,
104+ classname : customClass ,
131105 } ,
132106 suggest :
133107 range [ 0 ] && range [ 1 ]
134108 ? [
135109 {
136110 messageId : "fix:unknown-classname:remove" ,
137111 data : {
138- classname : cls ,
112+ classname : customClass ,
139113 } ,
140114 fix : ( fixer ) =>
141115 fixer . replaceTextRange ( [ start , end ] , patchedValue ) ,
0 commit comments