Skip to content

Commit a7b7c4c

Browse files
committed
essential fixes
1 parent ce4749e commit a7b7c4c

File tree

4 files changed

+94
-46
lines changed

4 files changed

+94
-46
lines changed

lib/rules/input-components-require-accessible-name.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,12 @@ const rule = ESLintUtils.RuleCreator.withoutDocs({
4242
return;
4343
}
4444

45+
console.log("aria-label::: ", hasNonEmptyProp(node.attributes, "aria-label"));
46+
console.log("hasFieldParent::: ", hasFieldParent(context));
47+
console.log("isInsideLabelTag::: ", isInsideLabelTag(context));
48+
console.log("hasAssociatedLabelViaHtmlFor::: ", hasAssociatedLabelViaHtmlFor(node, context));
49+
console.log("hasAssociatedLabelViaAriaLabelledBy::: ", hasAssociatedLabelViaAriaLabelledBy(node, context));
50+
4551
// wrapped in Label tag, labelled with htmlFor, labelled with aria-labelledby
4652
if (
4753
hasNonEmptyProp(node.attributes, "aria-label") ||

lib/util/labelUtils.ts

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,17 @@ const hasLabelWithHtmlForId = (idValue: string, context: TSESLint.RuleContext<st
4040
return false;
4141
}
4242
const sourceCode = context.getSourceCode();
43-
const regex = /<Label[^>]*htmlFor[^>]*=[^>]*[{"|{'|"|']([^>'"}]*)['|"|'}|"}][^>]*>/gim;
44-
const matches = regex.exec(sourceCode.text);
45-
return !!matches && matches.some(match => match === idValue);
43+
console.log("sourceCode", sourceCode.getText()); // Optional debugging
44+
45+
const regex = /<(Label|label)[^>]*htmlFor[^>]*=["{']([^"'{}]*)["'}]/gi;
46+
let match;
47+
while ((match = regex.exec(sourceCode.text)) !== null) {
48+
// `match[2]` contains the `htmlFor` attribute value
49+
if (match[2] === idValue) {
50+
return true;
51+
}
52+
}
53+
return false;
4654
};
4755

4856
/**
@@ -59,10 +67,16 @@ const hasLabelWithHtmlId = (idValue: string, context: TSESLint.RuleContext<strin
5967
}
6068
const sourceCode = context.getSourceCode();
6169
console.log("sourceCode", sourceCode.getText());
62-
const regex = /<Label[^>]*id[^>]*=[^>]*[{"|{'|"|']([^>'"}]*)['|"|'}|"}][^>]*>/gim;
6370

64-
const matches = regex.exec(sourceCode.text);
65-
return !!matches && matches.some(match => match === idValue);
71+
const regex = /<(Label|label)[^>]*id[^>]*=["{']([^"'{}]*)["'}]/gi;
72+
let match;
73+
while ((match = regex.exec(sourceCode.text)) !== null) {
74+
// match[2] should contain the id value
75+
if (match[2] === idValue) {
76+
return true;
77+
}
78+
}
79+
return false;
6680
};
6781

6882
/***
@@ -79,10 +93,18 @@ const hasOtherElementWithHtmlId = (idValue: string, context: TSESLint.RuleContex
7993
return false;
8094
}
8195
const sourceCode: string = context.getSourceCode().text;
82-
const regex = /<(div|span|p|h[1-6])[^>]*id[^>]*=[^>]*[{"|{'|"|']([^>'"}]*)['|"|'}|"}][^>]*>/gim;
83-
84-
const matches = regex.exec(sourceCode);
85-
return !!matches && matches.some(match => match === idValue);
96+
console.log("sourceCode", sourceCode); // For debugging, if needed
97+
98+
// Adjusted regex pattern for elements with `id` attribute
99+
const regex = /<(div|span|p|h[1-6])[^>]*id[^>]*=["{']([^"'{}]*)["'}]/gi;
100+
let match;
101+
while ((match = regex.exec(sourceCode)) !== null) {
102+
// `match[2]` contains the `id` value in each matched element
103+
if (match[2] === idValue) {
104+
return true;
105+
}
106+
}
107+
return false;
86108
};
87109

88110
/**
@@ -99,6 +121,7 @@ const hasAssociatedLabelViaAriaLabelledBy = (
99121
context: TSESLint.RuleContext<string, unknown[]>
100122
): boolean => {
101123
const _hasAriaLabelledBy = hasNonEmptyProp(openingElement.attributes, "aria-labelledby");
124+
console.log(" --- _hasAriaLabelledBy::", _hasAriaLabelledBy);
102125
const prop = getProp(openingElement.attributes as unknown as JSXOpeningElement["attributes"], "aria-labelledby");
103126

104127
// Check if the prop exists before passing it to getPropValue
@@ -110,7 +133,10 @@ const hasAssociatedLabelViaAriaLabelledBy = (
110133
}
111134

112135
const hasHtmlId = hasLabelWithHtmlId(idValue, context);
136+
console.log(" --- hasHtmlId::", hasHtmlId);
137+
113138
const hasElementWithHtmlId = hasOtherElementWithHtmlId(idValue, context);
139+
console.log(" --- hasElementWithHtmlId:::", hasElementWithHtmlId);
114140

115141
return _hasAriaLabelledBy && (hasHtmlId || hasElementWithHtmlId);
116142
};

tests/lib/rules/input-components-require-accessible-name.test.ts

Lines changed: 39 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -31,39 +31,40 @@ function generateTestCases(labelComponent: string, componentName: string) {
3131
function generateTestCasesLabel(labelComponent: string, componentName: string) {
3232
return {
3333
valid: [
34-
`<><${labelComponent} htmlFor="some-id">Some Label</${labelComponent}><${componentName} id="some-id"/></>`,
35-
`<><${labelComponent} id="test-span">Some Label</${labelComponent}><${componentName} id="some-id" aria-labelledby="test-span"/></>`,
36-
`<${labelComponent}>test</${labelComponent}>`,
37-
`<${labelComponent}>test<${componentName} /></${labelComponent}>`,
38-
`<${labelComponent}>test<SomeNesting><${componentName} /></SomeNesting></${labelComponent}>`,
39-
`<Field label="this is my label"><${componentName} /></Field>`,
40-
`<${componentName} aria-label="this is my component" />`
34+
// `<><${labelComponent} htmlFor="some-id">Some Label</${labelComponent}><${componentName} id="some-id"/></>`,
35+
// `<><${labelComponent} id="test-span">Some Label</${labelComponent}><${componentName} id="some-id" aria-labelledby="test-span"/></>`,
36+
// `<${labelComponent}>test</${labelComponent}>`,
37+
// `<${labelComponent}>test<${componentName} /></${labelComponent}>`,
38+
// `<${labelComponent}>test<SomeNesting><${componentName} /></SomeNesting></${labelComponent}>`,
39+
// `<Field label="this is my label"><${componentName} /></Field>`,
40+
// `<${componentName} aria-label="this is my component" />`,
41+
`<><${labelComponent} id="paragraph_label-2">type here</${labelComponent}><${componentName} aria-labelledby="paragraph_label-2"></${componentName}><${labelComponent} id="paragraph_label-3">type here</${labelComponent}><${componentName} aria-labelledby="paragraph_label-3"></${componentName}></>`
4142
],
4243
invalid: [
43-
{
44-
code: `<><${componentName}/></>`,
45-
errors: [{ messageId: "missingLabelOnInput" }]
46-
},
47-
{
48-
code: `<><${labelComponent}/><${componentName}/></>`,
49-
errors: [{ messageId: "missingLabelOnInput" }]
50-
},
51-
{
52-
code: `<><${labelComponent} htmlFor="id"/><${componentName} /></>`,
53-
errors: [{ messageId: "missingLabelOnInput" }]
54-
},
55-
{
56-
code: `<${componentName} id="some-id"/>`,
57-
errors: [{ messageId: "missingLabelOnInput" }]
58-
},
59-
{
60-
code: `<><${labelComponent}>Some Label</${labelComponent}><${componentName} id="some-id"/></>`,
61-
errors: [{ messageId: "missingLabelOnInput" }]
62-
},
63-
{
64-
code: `<><Field></Field><${componentName} id="some-id"/></>`,
65-
errors: [{ messageId: "missingLabelOnInput" }]
66-
}
44+
// {
45+
// code: `<><${componentName}/></>`,
46+
// errors: [{ messageId: "missingLabelOnInput" }]
47+
// },
48+
// {
49+
// code: `<><${labelComponent}/><${componentName}/></>`,
50+
// errors: [{ messageId: "missingLabelOnInput" }]
51+
// },
52+
// {
53+
// code: `<><${labelComponent} htmlFor="id"/><${componentName} /></>`,
54+
// errors: [{ messageId: "missingLabelOnInput" }]
55+
// },
56+
// {
57+
// code: `<${componentName} id="some-id"/>`,
58+
// errors: [{ messageId: "missingLabelOnInput" }]
59+
// },
60+
// {
61+
// code: `<><${labelComponent}>Some Label</${labelComponent}><${componentName} id="some-id"/></>`,
62+
// errors: [{ messageId: "missingLabelOnInput" }]
63+
// },
64+
// {
65+
// code: `<><Field></Field><${componentName} id="some-id"/></>`,
66+
// errors: [{ messageId: "missingLabelOnInput" }]
67+
// }
6768
]
6869
};
6970
}
@@ -72,13 +73,15 @@ function generateAllTestCases() {
7273
const testSets: any[] = [];
7374

7475
// For each input-based component, generate test cases
75-
applicableComponents.forEach(components => {
76-
elementsUsedAsLabels.forEach(labels => {
77-
testSets.push(generateTestCases(labels, components));
78-
});
76+
["Input"].forEach(components => {
77+
// applicableComponents.forEach(components => {
78+
// elementsUsedAsLabels.forEach(labels => {
79+
// testSets.push(generateTestCases(labels, components));
80+
// });
7981

8082
// Also generate test cases for each native DOM element
81-
labelBasedComponents.forEach(labels => {
83+
["Label"].forEach(labels => {
84+
// labelBasedComponents.forEach(labels => {
8285
testSets.push(generateTestCasesLabel(labels, components));
8386
});
8487
});

tests/lib/rules/utils/labelUtils.test.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,19 @@ describe("labelUtils", () => {
7979
expect(result).toBe(true);
8080
});
8181

82+
test("returns true if aria-labelledby references an existing label element without duplicates", () => {
83+
const customContext: TSESLint.RuleContext<string, unknown[]> = {
84+
getSourceCode: () => ({
85+
getText: () => "<Label id='existing-label-id'>Test Label</Label><Label id='existing-label-id-2'>Test Label</Label>",
86+
text: () => "<Label id='existing-label-id'>Test Label</Label>"
87+
})
88+
} as unknown as TSESLint.RuleContext<string, unknown[]>;
89+
90+
openingElement.attributes = [createJSXAttribute("aria-labelledby", "existing-label-id")];
91+
const result = hasAssociatedLabelViaAriaLabelledBy(openingElement, customContext);
92+
expect(result).toBe(true);
93+
});
94+
8295
test("returns true if aria-labelledby references an existing non-label element", () => {
8396
const customContext: TSESLint.RuleContext<string, unknown[]> = {
8497
getSourceCode: () => ({

0 commit comments

Comments
 (0)