Skip to content

Commit 2c905ab

Browse files
rafaelss95mgechev
authored andcommitted
fix(no-input-rename): aria attributes not being allowed to be renamed (#665)
1 parent 6dab8d7 commit 2c905ab

File tree

2 files changed

+75
-1
lines changed

2 files changed

+75
-1
lines changed

src/noInputRenameRule.ts

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,48 @@ export const getFailureMessage = (className: string, propertyName: string): stri
3030
return sprintf(Rule.FAILURE_STRING, className, propertyName);
3131
};
3232

33+
const kebabToCamelCase = (value: string) => value.replace(/-[a-zA-Z]/g, x => x[1].toUpperCase());
34+
35+
// source: https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques
36+
const whiteListAliases = new Set<string>([
37+
'aria-activedescendant',
38+
'aria-atomic',
39+
'aria-autocomplete',
40+
'aria-busy',
41+
'aria-checked',
42+
'aria-controls',
43+
'aria-current',
44+
'aria-describedby',
45+
'aria-disabled',
46+
'aria-dragged',
47+
'aria-dropeffect',
48+
'aria-expanded',
49+
'aria-flowto',
50+
'aria-haspopup',
51+
'aria-hidden',
52+
'aria-invalid',
53+
'aria-label',
54+
'aria-labelledby',
55+
'aria-level',
56+
'aria-live',
57+
'aria-multiline',
58+
'aria-multiselectable',
59+
'aria-orientation',
60+
'aria-owns',
61+
'aria-posinset',
62+
'aria-pressed',
63+
'aria-readonly',
64+
'aria-relevant',
65+
'aria-required',
66+
'aria-selected',
67+
'aria-setsize',
68+
'aria-sort',
69+
'aria-valuemax',
70+
'aria-valuemin',
71+
'aria-valuenow',
72+
'aria-valuetext'
73+
]);
74+
3375
export class InputMetadataWalker extends NgWalker {
3476
private directiveSelectors!: ReadonlySet<DirectiveMetadata['selector']>;
3577

@@ -44,7 +86,10 @@ export class InputMetadataWalker extends NgWalker {
4486
}
4587

4688
private canPropertyBeAliased(propertyAlias: string, propertyName: string): boolean {
47-
return !!(this.directiveSelectors && this.directiveSelectors.has(propertyAlias) && propertyAlias !== propertyName);
89+
return !!(
90+
(this.directiveSelectors && this.directiveSelectors.has(propertyAlias) && propertyAlias !== propertyName) ||
91+
(whiteListAliases.has(propertyAlias) && propertyName === kebabToCamelCase(propertyAlias))
92+
);
4893
}
4994

5095
private validateInput(property: ts.PropertyDeclaration, input: ts.Decorator, args: string[]) {

test/noInputRenameRule.spec.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,23 @@ describe(ruleName, () => {
9494
source
9595
});
9696
});
97+
98+
it("should fail when an input alias is kebab-cased and whitelisted, but the property doesn't match the alias", () => {
99+
const source = `
100+
@Directive({
101+
selector: 'foo'
102+
})
103+
class TestDirective {
104+
@Input('aria-invalid') ariaBusy: string;
105+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
106+
}
107+
`;
108+
assertAnnotated({
109+
message: getFailureMessage('TestDirective', 'ariaBusy'),
110+
ruleName,
111+
source
112+
});
113+
});
97114
});
98115
});
99116

@@ -146,6 +163,18 @@ describe(ruleName, () => {
146163
`;
147164
assertSuccess(ruleName, source);
148165
});
166+
167+
it('should succeed when an input alias is kebab-cased and whitelisted', () => {
168+
const source = `
169+
@Directive({
170+
selector: 'foo'
171+
})
172+
class TestDirective {
173+
@Input('aria-label') ariaLabel: string;
174+
}
175+
`;
176+
assertSuccess(ruleName, source);
177+
});
149178
});
150179
});
151180
});

0 commit comments

Comments
 (0)