Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 71a34ef

Browse files
committed
chore(lint): add combobox api check
Signed-off-by: Cory Rylan <[email protected]>
1 parent c961584 commit 71a34ef

2 files changed

Lines changed: 77 additions & 17 deletions

File tree

projects/lint/src/eslint/rules/no-deprecated-attributes.test.ts

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,19 @@ describe('noDeprecatedAttributes', () => {
3636
expect(noDeprecatedAttributes.meta.messages['unexpected-deprecated-attribute']).toBe(
3737
'Unexpected use of deprecated value "{{value}}" in attribute "{{attribute}}"'
3838
);
39+
expect(noDeprecatedAttributes.meta.messages['unexpected-deprecated-attribute-replacement']).toBe(
40+
'Unexpected use of deprecated attribute "{{attribute}}". Use {{replacement}} instead.'
41+
);
3942
});
4043

4144
it('should allow valid use of attributes', () => {
4245
tester.run('should allow valid use of attributes', rule, {
4346
valid: [
4447
'<nve-badge></nve-badge>',
4548
'<nve-badge status="success"></nve-badge>',
46-
`<nve-badge status=${'success'}></nve-badge>`
49+
`<nve-badge status=${'success'}></nve-badge>`,
50+
'<nve-combobox tag-layout="hidden"></nve-combobox>',
51+
'<nve-combobox tag-layout="wrap"></nve-combobox>'
4752
],
4853
invalid: []
4954
});
@@ -66,6 +71,26 @@ describe('noDeprecatedAttributes', () => {
6671
errors: [
6772
{ messageId: 'unexpected-deprecated-attribute', data: { attribute: 'status', value: 'trend-neutral' } }
6873
]
74+
},
75+
{
76+
code: '<nve-combobox notags></nve-combobox>',
77+
output: '<nve-combobox tag-layout="hidden"></nve-combobox>',
78+
errors: [
79+
{
80+
messageId: 'unexpected-deprecated-attribute-replacement',
81+
data: { attribute: 'notags', replacement: 'tag-layout="hidden"' }
82+
}
83+
]
84+
},
85+
{
86+
code: '<nve-combobox notags="true"></nve-combobox>',
87+
output: '<nve-combobox tag-layout="hidden"></nve-combobox>',
88+
errors: [
89+
{
90+
messageId: 'unexpected-deprecated-attribute-replacement',
91+
data: { attribute: 'notags', replacement: 'tag-layout="hidden"' }
92+
}
93+
]
6994
}
7095
]
7196
});

projects/lint/src/eslint/rules/no-deprecated-attributes.ts

Lines changed: 51 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,58 @@
44
import type { Rule } from 'eslint';
55
import { createVisitors } from '@html-eslint/eslint-plugin/lib/rules/utils/visitors.js';
66
import { findAttr } from '@html-eslint/eslint-plugin/lib/rules/utils/node.js';
7-
import type { HtmlTagNode } from '../rule-types.js';
7+
import type { HtmlAttribute, HtmlTagNode } from '../rule-types.js';
88

99
declare const __ELEMENTS_PAGES_BASE_URL__: string;
10-
const DEPRECATED_ATTRIBUTES = {
10+
11+
interface DeprecatedAttributeConfig {
12+
replacement?: string;
13+
values?: string[];
14+
}
15+
16+
interface DeprecatedAttributeReport {
17+
attr: HtmlAttribute;
18+
attribute: string;
19+
config: DeprecatedAttributeConfig;
20+
}
21+
22+
const DEPRECATED_ATTRIBUTES: Record<string, Record<string, DeprecatedAttributeConfig>> = {
1123
'nve-badge': {
12-
status: ['trend-up', 'trend-down', 'trend-neutral']
24+
status: { values: ['trend-up', 'trend-down', 'trend-neutral'] }
25+
},
26+
'nve-combobox': {
27+
notags: { replacement: 'tag-layout="hidden"' }
1328
}
1429
};
1530

31+
function attributeValueIsDeprecated(config: DeprecatedAttributeConfig, value?: string) {
32+
return !config.values || (!!value && config.values.includes(value));
33+
}
34+
35+
function reportDeprecatedAttribute(context: Rule.RuleContext, { attr, attribute, config }: DeprecatedAttributeReport) {
36+
const replacement = config.replacement;
37+
const messageId = config.replacement
38+
? 'unexpected-deprecated-attribute-replacement'
39+
: 'unexpected-deprecated-attribute';
40+
const report: Rule.ReportDescriptor = {
41+
node: attr,
42+
data: {
43+
attribute,
44+
replacement: config.replacement ?? '',
45+
value: attr.value?.value ?? ''
46+
},
47+
messageId
48+
};
49+
if (replacement) {
50+
report.fix = fixer => fixer.replaceText(attr, replacement);
51+
}
52+
context.report(report);
53+
}
54+
1655
const rule = {
1756
meta: {
1857
type: 'problem' as const,
58+
fixable: 'code' as const,
1959
docs: {
2060
description: 'Disallow use of deprecated attributes in HTML.',
2161
category: 'Best Practice',
@@ -24,27 +64,22 @@ const rule = {
2464
},
2565
schema: [],
2666
messages: {
27-
['unexpected-deprecated-attribute']: 'Unexpected use of deprecated value "{{value}}" in attribute "{{attribute}}"'
67+
['unexpected-deprecated-attribute']:
68+
'Unexpected use of deprecated value "{{value}}" in attribute "{{attribute}}"',
69+
['unexpected-deprecated-attribute-replacement']:
70+
'Unexpected use of deprecated attribute "{{attribute}}". Use {{replacement}} instead.'
2871
}
2972
},
3073
create(context: Rule.RuleContext) {
3174
return createVisitors(context, {
3275
Tag(node: HtmlTagNode) {
33-
const deprecatedAttributes: Record<string, string[]> | undefined =
76+
const deprecatedAttributes: Record<string, DeprecatedAttributeConfig> | undefined =
3477
DEPRECATED_ATTRIBUTES[node.name as keyof typeof DEPRECATED_ATTRIBUTES];
3578
if (deprecatedAttributes) {
36-
Object.entries(deprecatedAttributes).forEach(([attribute, values]) => {
79+
Object.entries(deprecatedAttributes).forEach(([attribute, config]) => {
3780
const attr = findAttr(node, attribute);
38-
const value = attr?.value?.value;
39-
if (attr && values.includes(value)) {
40-
context.report({
41-
node: attr,
42-
data: {
43-
attribute,
44-
value
45-
},
46-
messageId: 'unexpected-deprecated-attribute'
47-
});
81+
if (attr && attributeValueIsDeprecated(config, attr.value?.value)) {
82+
reportDeprecatedAttribute(context, { attr, attribute, config });
4883
}
4984
});
5085
}

0 commit comments

Comments
 (0)