Skip to content

Commit acb3d65

Browse files
committed
Add autofix support for the form-method-require rule
implemented autofix support for the `form-method-require` rule. - ✅ Added createFormMethodRequireFix() function in htmlhint-server/src/server.ts - ✅ Added the new rule to the autofix switch statement - ✅ Updated README.md to document the new autofix support - ✅ Compiled successfully with no errors The autofix will add an empty method="" attribute, leaving the cursor positioned so users can easily fill in get, post, or dialog as needed.
1 parent 921e2dc commit acb3d65

File tree

3 files changed

+108
-0
lines changed

3 files changed

+108
-0
lines changed

htmlhint-server/src/server.ts

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1966,6 +1966,108 @@ function createAttrNoDuplicationFix(
19661966
};
19671967
}
19681968

1969+
/**
1970+
* Create auto-fix action for form-method-require rule
1971+
*/
1972+
function createFormMethodRequireFix(
1973+
document: TextDocument,
1974+
diagnostic: Diagnostic,
1975+
): CodeAction | null {
1976+
trace(
1977+
`[DEBUG] createFormMethodRequireFix called with diagnostic: ${JSON.stringify(diagnostic)}`,
1978+
);
1979+
1980+
if (!diagnostic.data || diagnostic.data.ruleId !== "form-method-require") {
1981+
trace(
1982+
`[DEBUG] createFormMethodRequireFix: Invalid diagnostic data or ruleId`,
1983+
);
1984+
return null;
1985+
}
1986+
1987+
const text = document.getText();
1988+
const diagnosticOffset = document.offsetAt(diagnostic.range.start);
1989+
1990+
// Use robust tag boundary detection to find the form tag
1991+
const tagBoundaries = findTagBoundaries(text, diagnosticOffset);
1992+
if (!tagBoundaries) {
1993+
trace(`[DEBUG] createFormMethodRequireFix: Could not find tag boundaries`);
1994+
return null;
1995+
}
1996+
1997+
const { tagStart, tagEnd } = tagBoundaries;
1998+
const tagContent = text.substring(tagStart, tagEnd + 1);
1999+
trace(`[DEBUG] createFormMethodRequireFix: Found tag: ${tagContent}`);
2000+
2001+
// Verify this is a form tag
2002+
const formTagMatch = tagContent.match(/^<\s*form\b/i);
2003+
if (!formTagMatch) {
2004+
trace(`[DEBUG] createFormMethodRequireFix: Not a form tag`);
2005+
return null;
2006+
}
2007+
2008+
// Check if method attribute already exists
2009+
const methodAttrMatch = tagContent.match(/\bmethod\s*=/i);
2010+
if (methodAttrMatch) {
2011+
trace(
2012+
`[DEBUG] createFormMethodRequireFix: Method attribute already exists`,
2013+
);
2014+
return null;
2015+
}
2016+
2017+
// Find the best position to insert the method attribute
2018+
// We'll add it after the opening form tag name but before the closing >
2019+
const formMatch = tagContent.match(/^(<\s*form)(\s+[^>]*?)?(\/?\s*>)$/i);
2020+
if (!formMatch) {
2021+
trace(
2022+
`[DEBUG] createFormMethodRequireFix: Could not parse form tag structure`,
2023+
);
2024+
return null;
2025+
}
2026+
2027+
const beforeAttrs = formMatch[1]; // "<form"
2028+
const existingAttrs = formMatch[2] || ""; // existing attributes
2029+
const tagClose = formMatch[3]; // ">" or "/>"
2030+
2031+
// Calculate insertion position
2032+
let insertPosition: number;
2033+
let newText: string;
2034+
2035+
if (existingAttrs.trim()) {
2036+
// There are existing attributes, add method after them
2037+
insertPosition = tagStart + beforeAttrs.length + existingAttrs.length;
2038+
newText = ' method=""';
2039+
} else {
2040+
// No existing attributes, add method right after "form"
2041+
insertPosition = tagStart + beforeAttrs.length;
2042+
newText = ' method=""';
2043+
}
2044+
2045+
const edit: TextEdit = {
2046+
range: {
2047+
start: document.positionAt(insertPosition),
2048+
end: document.positionAt(insertPosition),
2049+
},
2050+
newText: newText,
2051+
};
2052+
2053+
trace(
2054+
`[DEBUG] createFormMethodRequireFix: Will insert "${newText}" at position ${insertPosition}`,
2055+
);
2056+
2057+
const workspaceEdit: WorkspaceEdit = {
2058+
changes: {
2059+
[document.uri]: [edit],
2060+
},
2061+
};
2062+
2063+
return {
2064+
title: 'Add method="" attribute to form',
2065+
kind: CodeActionKind.QuickFix,
2066+
edit: workspaceEdit,
2067+
isPreferred: true,
2068+
};
2069+
}
2070+
19692071
/**
19702072
* Create auto-fix actions for supported rules
19712073
*/
@@ -2064,6 +2166,10 @@ async function createAutoFixes(
20642166
trace(`[DEBUG] Calling createAttrNoDuplicationFix`);
20652167
fix = createAttrNoDuplicationFix(document, diagnostic);
20662168
break;
2169+
case "form-method-require":
2170+
trace(`[DEBUG] Calling createFormMethodRequireFix`);
2171+
fix = createFormMethodRequireFix(document, diagnostic);
2172+
break;
20672173
default:
20682174
trace(`[DEBUG] No autofix function found for rule: ${ruleId}`);
20692175
break;

htmlhint/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ All notable changes to the "vscode-htmlhint" extension will be documented in thi
55
### v1.14.0 (2025-11-26)
66

77
- Add autofix for the `attr-no-duplication` rule
8+
- Add autofix for the `form-method-require` rule
89

910
### v1.13.0 (2025-11-25)
1011

htmlhint/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ The extension provides automatic fixes for many common HTML issues. Currently su
3535
- **`button-type-require`** - Adds type attribute to buttons
3636
- **`doctype-first`** - Adds DOCTYPE declaration at the beginning
3737
- **`doctype-html5`** - Updates DOCTYPE to HTML5
38+
- **`form-method-require`** - Adds empty method attribute to forms
3839
- **`html-lang-require`** - Adds `lang` attribute to `<html>` tag
3940
- **`meta-charset-require`** - Adds charset meta tag
4041
- **`meta-description-require`** - Adds description meta tag

0 commit comments

Comments
 (0)