Skip to content

Commit a245dea

Browse files
authored
Merge pull request #337 from htmlhint/dev/coliff/add-autofix-for-form-method-require
Add autofix support for the `form-method-require` rule
2 parents 921e2dc + 349df24 commit a245dea

File tree

3 files changed

+105
-0
lines changed

3 files changed

+105
-0
lines changed

htmlhint-server/src/server.ts

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1966,6 +1966,105 @@ 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+
2030+
// Calculate insertion position
2031+
const newText = ' method=""';
2032+
let insertPosition: number;
2033+
2034+
if (existingAttrs.trim()) {
2035+
// There are existing attributes, add method after them
2036+
insertPosition = tagStart + beforeAttrs.length + existingAttrs.length;
2037+
} else {
2038+
// No existing attributes, add method right after "form"
2039+
insertPosition = tagStart + beforeAttrs.length;
2040+
}
2041+
2042+
const edit: TextEdit = {
2043+
range: {
2044+
start: document.positionAt(insertPosition),
2045+
end: document.positionAt(insertPosition),
2046+
},
2047+
newText: newText,
2048+
};
2049+
2050+
trace(
2051+
`[DEBUG] createFormMethodRequireFix: Will insert "${newText}" at position ${insertPosition}`,
2052+
);
2053+
2054+
const workspaceEdit: WorkspaceEdit = {
2055+
changes: {
2056+
[document.uri]: [edit],
2057+
},
2058+
};
2059+
2060+
return {
2061+
title: 'Add method="" attribute to form',
2062+
kind: CodeActionKind.QuickFix,
2063+
edit: workspaceEdit,
2064+
isPreferred: true,
2065+
};
2066+
}
2067+
19692068
/**
19702069
* Create auto-fix actions for supported rules
19712070
*/
@@ -2064,6 +2163,10 @@ async function createAutoFixes(
20642163
trace(`[DEBUG] Calling createAttrNoDuplicationFix`);
20652164
fix = createAttrNoDuplicationFix(document, diagnostic);
20662165
break;
2166+
case "form-method-require":
2167+
trace(`[DEBUG] Calling createFormMethodRequireFix`);
2168+
fix = createFormMethodRequireFix(document, diagnostic);
2169+
break;
20672170
default:
20682171
trace(`[DEBUG] No autofix function found for rule: ${ruleId}`);
20692172
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)