@@ -262,6 +262,67 @@ function loadConfigurationFile(configFile: string): HtmlHintConfig | null {
262262 return ruleset ;
263263}
264264
265+ function isHtmlHintRuleEnabled ( value : unknown ) : boolean {
266+ if ( value === undefined || value === null ) {
267+ return false ;
268+ }
269+
270+ if ( Array . isArray ( value ) ) {
271+ if ( value . length === 0 ) {
272+ return false ;
273+ }
274+ return isHtmlHintRuleEnabled ( value [ 0 ] ) ;
275+ }
276+
277+ if ( typeof value === "boolean" ) {
278+ return value ;
279+ }
280+
281+ if ( typeof value === "number" ) {
282+ return value !== 0 ;
283+ }
284+
285+ if ( typeof value === "string" ) {
286+ const normalized = value . trim ( ) . toLowerCase ( ) ;
287+ return normalized !== "false" && normalized !== "0" && normalized !== "" ;
288+ }
289+
290+ if ( typeof value === "object" ) {
291+ return true ;
292+ }
293+
294+ return false ;
295+ }
296+
297+ function isRuleEnabledForDocument (
298+ document : TextDocument ,
299+ ruleId : string ,
300+ ) : boolean {
301+ try {
302+ const parsedUri = URI . parse ( document . uri ) ;
303+
304+ if ( parsedUri . scheme !== "file" ) {
305+ trace (
306+ `[DEBUG] isRuleEnabledForDocument: Non-file scheme for ${ document . uri } , rule ${ ruleId } treated as disabled` ,
307+ ) ;
308+ return false ;
309+ }
310+
311+ const config = getConfiguration ( parsedUri . fsPath ) ;
312+ const ruleValue = ( config as Record < string , unknown > ) [ ruleId ] ;
313+ const enabled = isHtmlHintRuleEnabled ( ruleValue ) ;
314+ trace (
315+ `[DEBUG] isRuleEnabledForDocument: Rule ${ ruleId } enabled=${ enabled } for ${ document . uri } ` ,
316+ ) ;
317+ return enabled ;
318+ } catch ( error ) {
319+ trace (
320+ `[DEBUG] isRuleEnabledForDocument: Failed to determine rule ${ ruleId } for ${ document . uri } : ${ error } ` ,
321+ ) ;
322+ return false ;
323+ }
324+ }
325+
265326function isErrorWithMessage ( err : unknown ) : err is { message : string } {
266327 return (
267328 typeof err === "object" &&
@@ -789,7 +850,9 @@ function createMetaCharsetRequireFix(
789850 // Insert charset meta tag at the beginning of head (right after <head>)
790851 const headStart = headMatch . index ! + headMatch [ 0 ] . indexOf ( ">" ) + 1 ;
791852 const insertPosition = headStart ;
792- const newText = '\n <meta charset="UTF-8">' ;
853+ const shouldSelfClose = isRuleEnabledForDocument ( document , "tag-self-close" ) ;
854+ const newText =
855+ '\n <meta charset="UTF-8"' + ( shouldSelfClose ? " />" : ">" ) ;
793856
794857 const edit : TextEdit = {
795858 range : {
@@ -846,27 +909,28 @@ function createMetaViewportRequireFix(
846909 / < m e t a \s + c h a r s e t \s * = \s * [ " ' ] [ ^ " ' ] * [ " ' ] [ ^ > ] * > / i,
847910 ) ;
848911
912+ const shouldSelfClose = isRuleEnabledForDocument ( document , "tag-self-close" ) ;
913+ trace (
914+ `[DEBUG] createMetaViewportRequireFix: tag-self-close enabled=${ shouldSelfClose } ` ,
915+ ) ;
916+ const viewportSnippet = `\n <meta name="viewport" content="width=device-width, initial-scale=1.0"${ shouldSelfClose ? " />" : ">" } ` ;
917+
849918 let insertPosition : number ;
850- let newText : string ;
851919
852920 if ( metaCharsetMatch ) {
853921 const metaCharsetEnd =
854922 headStart + metaCharsetMatch . index ! + metaCharsetMatch [ 0 ] . length ;
855923 insertPosition = metaCharsetEnd ;
856- newText =
857- '\n <meta name="viewport" content="width=device-width, initial-scale=1.0">' ;
858924 } else {
859925 insertPosition = headStart ;
860- newText =
861- '\n <meta name="viewport" content="width=device-width, initial-scale=1.0">' ;
862926 }
863927
864928 const edit : TextEdit = {
865929 range : {
866930 start : document . positionAt ( insertPosition ) ,
867931 end : document . positionAt ( insertPosition ) ,
868932 } ,
869- newText : newText ,
933+ newText : viewportSnippet ,
870934 } ;
871935
872936 const workspaceEdit : WorkspaceEdit = {
@@ -923,32 +987,32 @@ function createMetaDescriptionRequireFix(
923987 ) ;
924988
925989 let insertPosition : number ;
926- let newText : string ;
990+ const shouldSelfClose = isRuleEnabledForDocument ( document , "tag-self-close" ) ;
991+ const descriptionSnippet =
992+ '\n <meta name="description" content=""' +
993+ ( shouldSelfClose ? " />" : ">" ) ;
927994
928995 if ( metaViewportMatch ) {
929996 // Insert after viewport meta tag
930997 const metaViewportEnd =
931998 headStart + metaViewportMatch . index ! + metaViewportMatch [ 0 ] . length ;
932999 insertPosition = metaViewportEnd ;
933- newText = '\n <meta name="description" content="">' ;
9341000 } else if ( metaCharsetMatch ) {
9351001 // Insert after charset meta tag
9361002 const metaCharsetEnd =
9371003 headStart + metaCharsetMatch . index ! + metaCharsetMatch [ 0 ] . length ;
9381004 insertPosition = metaCharsetEnd ;
939- newText = '\n <meta name="description" content="">' ;
9401005 } else {
9411006 // Insert at the beginning of head
9421007 insertPosition = headStart ;
943- newText = '\n <meta name="description" content="">' ;
9441008 }
9451009
9461010 const edit : TextEdit = {
9471011 range : {
9481012 start : document . positionAt ( insertPosition ) ,
9491013 end : document . positionAt ( insertPosition ) ,
9501014 } ,
951- newText : newText ,
1015+ newText : descriptionSnippet ,
9521016 } ;
9531017
9541018 const workspaceEdit : WorkspaceEdit = {
@@ -1977,7 +2041,10 @@ function createAttrValueNoDuplicationFix(
19772041 `[DEBUG] createAttrValueNoDuplicationFix called with diagnostic: ${ JSON . stringify ( diagnostic ) } ` ,
19782042 ) ;
19792043
1980- if ( ! diagnostic . data || diagnostic . data . ruleId !== "attr-value-no-duplication" ) {
2044+ if (
2045+ ! diagnostic . data ||
2046+ diagnostic . data . ruleId !== "attr-value-no-duplication"
2047+ ) {
19812048 trace (
19822049 `[DEBUG] createAttrValueNoDuplicationFix: Invalid diagnostic data or ruleId` ,
19832050 ) ;
@@ -1990,7 +2057,9 @@ function createAttrValueNoDuplicationFix(
19902057 // Use robust tag boundary detection
19912058 const tagBoundaries = findTagBoundaries ( text , diagnosticOffset ) ;
19922059 if ( ! tagBoundaries ) {
1993- trace ( `[DEBUG] createAttrValueNoDuplicationFix: Could not find tag boundaries` ) ;
2060+ trace (
2061+ `[DEBUG] createAttrValueNoDuplicationFix: Could not find tag boundaries` ,
2062+ ) ;
19942063 return null ;
19952064 }
19962065
@@ -2017,8 +2086,9 @@ function createAttrValueNoDuplicationFix(
20172086
20182087 if ( values . length !== uniqueValues . length ) {
20192088 // Found duplicates, create an edit to fix them
2020- const newAttrValue = uniqueValues . join ( ' ' ) ;
2021- const quote = match [ 2 ] !== undefined ? '"' : match [ 3 ] !== undefined ? "'" : '' ;
2089+ const newAttrValue = uniqueValues . join ( " " ) ;
2090+ const quote =
2091+ match [ 2 ] !== undefined ? '"' : match [ 3 ] !== undefined ? "'" : "" ;
20222092 const newFullMatch = quote
20232093 ? `${ attrName } =${ quote } ${ newAttrValue } ${ quote } `
20242094 : `${ attrName } =${ newAttrValue } ` ;
0 commit comments