Skip to content

Commit

Permalink
feat(eslint-plugin-template): [no-duplicate-attributes] Add option to…
Browse files Browse the repository at this point in the history
… ignore properties (#1104)
  • Loading branch information
ssams committed Sep 26, 2022
1 parent 9069282 commit 018d390
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 4 deletions.
Expand Up @@ -35,6 +35,12 @@ interface Options {
* Default: `true`
*/
allowTwoWayDataBinding?: boolean;
/**
* Input or output properties for which duplicate presence is allowed as an exception to the rule.
*
* Default: `[]`
*/
ignore?: string[];
}

```
Expand Down Expand Up @@ -346,6 +352,38 @@ interface Options {
~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
```

<br>

---

<br>

#### Custom Config

```json
{
"rules": {
"@angular-eslint/template/no-duplicate-attributes": [
"error",
{
"ignore": [
"class"
]
}
]
}
}
```

<br>

#### ❌ Invalid Code

```html
<input [name]="foo" class="css-static" name="bar" [class]="dynamic">
~~~~~~~~~~~~ ~~~~~~~~~~
```

</details>

<br>
Expand Down
Expand Up @@ -10,10 +10,18 @@ import {
} from '../utils/create-eslint-rule';
import { getOriginalAttributeName } from '../utils/get-original-attribute-name';

type Options = [{ readonly allowTwoWayDataBinding?: boolean }];
type Options = [
{
readonly allowTwoWayDataBinding?: boolean;
readonly ignore?: readonly string[];
},
];
export type MessageIds = 'noDuplicateAttributes' | 'suggestRemoveAttribute';
export const RULE_NAME = 'no-duplicate-attributes';
const DEFAULT_OPTIONS: Options[number] = { allowTwoWayDataBinding: true };
const DEFAULT_OPTIONS: Options[number] = {
allowTwoWayDataBinding: true,
ignore: [],
};

export default createESLintRule<Options, MessageIds>({
name: RULE_NAME,
Expand All @@ -34,6 +42,13 @@ export default createESLintRule<Options, MessageIds>({
default: DEFAULT_OPTIONS.allowTwoWayDataBinding,
description: `Whether or not two-way data binding is allowed as an exception to the rule.`,
},
ignore: {
type: 'array',
items: { type: 'string' },
uniqueItems: true,
default: DEFAULT_OPTIONS.ignore,
description: `Input or output properties for which duplicate presence is allowed as an exception to the rule.`,
},
},
additionalProperties: false,
},
Expand All @@ -44,7 +59,7 @@ export default createESLintRule<Options, MessageIds>({
},
},
defaultOptions: [DEFAULT_OPTIONS],
create(context, [{ allowTwoWayDataBinding }]) {
create(context, [{ allowTwoWayDataBinding, ignore }]) {
const parserServices = getTemplateParserServices(context);

return {
Expand All @@ -68,7 +83,15 @@ export default createESLintRule<Options, MessageIds>({
...duplicateOutputs,
] as const;

allDuplicates.forEach((duplicate) => {
const filteredDuplicates =
ignore && ignore.length > 0
? allDuplicates.filter(
(duplicate) =>
!ignore.includes(getOriginalAttributeName(duplicate)),
)
: allDuplicates;

filteredDuplicates.forEach((duplicate) => {
const loc = parserServices.convertNodeSourceSpanToLoc(
duplicate.sourceSpan,
);
Expand Down
Expand Up @@ -496,4 +496,44 @@ export const invalid = [
},
],
}),
convertAnnotatedSourceToFailureCase({
description: 'should not report ignored properties',
annotatedSource: `
<input [name]="foo" class="css-static" name="bar" [class]="dynamic">
~~~~~~~~~~~~ ^^^^^^^^^^
`,
options: [{ ignore: ['class'] }],
messages: [
{
char: '~',
messageId,
data: { attributeName: 'name' },
suggestions: [
{
messageId: suggestRemoveAttribute,
output: `
<input class="css-static" name="bar" [class]="dynamic">
`,
data: { attributeName: 'name' },
},
],
},
{
char: '^',
messageId,
data: { attributeName: 'name' },
suggestions: [
{
messageId: suggestRemoveAttribute,
output: `
<input [name]="foo" class="css-static" [class]="dynamic">
`,
data: { attributeName: 'name' },
},
],
},
],
}),
];

0 comments on commit 018d390

Please sign in to comment.