@db-ux/core-eslint-plugin 0.0.0 → 4.4.2-eslint-plugin2-696cb23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1 -0
- package/README.md +843 -0
- package/build/index.d.ts +352 -0
- package/build/index.js +82 -0
- package/build/rules/accordion/accordion-item-headline-required.d.ts +16 -0
- package/build/rules/accordion/accordion-item-headline-required.js +61 -0
- package/build/rules/accordion/no-nested-accordion.d.ts +16 -0
- package/build/rules/accordion/no-nested-accordion.js +54 -0
- package/build/rules/badge/badge-corner-placement-rules.d.ts +18 -0
- package/build/rules/badge/badge-corner-placement-rules.js +114 -0
- package/build/rules/badge/badge-no-inline-in-interactive.d.ts +17 -0
- package/build/rules/badge/badge-no-inline-in-interactive.js +129 -0
- package/build/rules/button/button-no-text-requires-tooltip.d.ts +18 -0
- package/build/rules/button/button-no-text-requires-tooltip.js +109 -0
- package/build/rules/button/button-single-icon-attribute.d.ts +16 -0
- package/build/rules/button/button-single-icon-attribute.js +49 -0
- package/build/rules/button/button-type-required.d.ts +17 -0
- package/build/rules/button/button-type-required.js +58 -0
- package/build/rules/close-button/close-button-text-required.d.ts +16 -0
- package/build/rules/close-button/close-button-text-required.js +38 -0
- package/build/rules/content/text-or-children-required.d.ts +16 -0
- package/build/rules/content/text-or-children-required.js +47 -0
- package/build/rules/form/form-label-required.d.ts +16 -0
- package/build/rules/form/form-label-required.js +45 -0
- package/build/rules/form/form-validation-message-required.d.ts +16 -0
- package/build/rules/form/form-validation-message-required.js +91 -0
- package/build/rules/header/header-burger-menu-label-required.d.ts +16 -0
- package/build/rules/header/header-burger-menu-label-required.js +43 -0
- package/build/rules/icon/prefer-icon-attribute.d.ts +17 -0
- package/build/rules/icon/prefer-icon-attribute.js +82 -0
- package/build/rules/input/input-file-type-validation.d.ts +18 -0
- package/build/rules/input/input-file-type-validation.js +50 -0
- package/build/rules/input/input-type-required.d.ts +17 -0
- package/build/rules/input/input-type-required.js +54 -0
- package/build/rules/link/link-external-security.d.ts +19 -0
- package/build/rules/link/link-external-security.js +166 -0
- package/build/rules/navigation/navigation-item-back-button-text-required.d.ts +16 -0
- package/build/rules/navigation/navigation-item-back-button-text-required.js +43 -0
- package/build/rules/select/custom-select-tags-remove-text-required.d.ts +16 -0
- package/build/rules/select/custom-select-tags-remove-text-required.js +33 -0
- package/build/rules/select/select-requires-options.d.ts +16 -0
- package/build/rules/select/select-requires-options.js +45 -0
- package/build/rules/tag/tag-removable-remove-button-required.d.ts +16 -0
- package/build/rules/tag/tag-removable-remove-button-required.js +49 -0
- package/build/rules/tooltip/no-interactive-tooltip-content.d.ts +15 -0
- package/build/rules/tooltip/no-interactive-tooltip-content.js +49 -0
- package/build/rules/tooltip/tooltip-requires-interactive-parent.d.ts +15 -0
- package/build/rules/tooltip/tooltip-requires-interactive-parent.js +47 -0
- package/build/shared/constants.d.ts +58 -0
- package/build/shared/constants.js +98 -0
- package/build/shared/utils.d.ts +54 -0
- package/build/shared/utils.js +178 -0
- package/package.json +37 -1
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { MESSAGE_IDS } from '../../shared/constants.js';
|
|
2
|
+
declare const _default: {
|
|
3
|
+
meta: {
|
|
4
|
+
type: string;
|
|
5
|
+
docs: {
|
|
6
|
+
description: string;
|
|
7
|
+
url: string;
|
|
8
|
+
};
|
|
9
|
+
messages: {
|
|
10
|
+
[MESSAGE_IDS.NAVIGATION_ITEM_MISSING_BACK_BUTTON_TEXT]: string;
|
|
11
|
+
};
|
|
12
|
+
schema: never[];
|
|
13
|
+
};
|
|
14
|
+
create(context: any): any;
|
|
15
|
+
};
|
|
16
|
+
export default _default;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { createAngularVisitors, defineTemplateBodyVisitor, getAttributeValue, isDBComponent } from '../../shared/utils.js';
|
|
2
|
+
import { COMPONENTS, MESSAGES, MESSAGE_IDS } from '../../shared/constants.js';
|
|
3
|
+
export default {
|
|
4
|
+
meta: {
|
|
5
|
+
type: 'problem',
|
|
6
|
+
docs: {
|
|
7
|
+
description: 'Ensure DBNavigationItem has backButtonText for accessibility',
|
|
8
|
+
url: 'https://github.com/db-ux-design-system/core-web/blob/main/packages/eslint-plugin/README.md#navigation-item-back-button-text-required'
|
|
9
|
+
},
|
|
10
|
+
messages: {
|
|
11
|
+
[MESSAGE_IDS.NAVIGATION_ITEM_MISSING_BACK_BUTTON_TEXT]: MESSAGES.NAVIGATION_ITEM_MISSING_BACK_BUTTON_TEXT
|
|
12
|
+
},
|
|
13
|
+
schema: []
|
|
14
|
+
},
|
|
15
|
+
create(context) {
|
|
16
|
+
const angularHandler = (node, parserServices) => {
|
|
17
|
+
const backButtonText = getAttributeValue(node, 'backButtonText');
|
|
18
|
+
if (!backButtonText) {
|
|
19
|
+
const loc = parserServices.convertNodeSourceSpanToLoc(node.sourceSpan);
|
|
20
|
+
context.report({
|
|
21
|
+
loc,
|
|
22
|
+
messageId: MESSAGE_IDS.NAVIGATION_ITEM_MISSING_BACK_BUTTON_TEXT
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
const angularVisitors = createAngularVisitors(context, COMPONENTS.DBNavigationItem, angularHandler);
|
|
27
|
+
if (angularVisitors)
|
|
28
|
+
return angularVisitors;
|
|
29
|
+
const checkNavigationItem = (node) => {
|
|
30
|
+
const openingElement = node.openingElement || node;
|
|
31
|
+
if (!isDBComponent(openingElement, COMPONENTS.DBNavigationItem))
|
|
32
|
+
return;
|
|
33
|
+
const backButtonText = getAttributeValue(openingElement, 'backButtonText');
|
|
34
|
+
if (!backButtonText) {
|
|
35
|
+
context.report({
|
|
36
|
+
node: openingElement,
|
|
37
|
+
messageId: MESSAGE_IDS.NAVIGATION_ITEM_MISSING_BACK_BUTTON_TEXT
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
return defineTemplateBodyVisitor(context, { VElement: checkNavigationItem, Element: checkNavigationItem }, { JSXElement: checkNavigationItem });
|
|
42
|
+
}
|
|
43
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { MESSAGE_IDS } from '../../shared/constants.js';
|
|
2
|
+
declare const _default: {
|
|
3
|
+
meta: {
|
|
4
|
+
type: string;
|
|
5
|
+
docs: {
|
|
6
|
+
description: string;
|
|
7
|
+
url: string;
|
|
8
|
+
};
|
|
9
|
+
messages: {
|
|
10
|
+
[MESSAGE_IDS.CUSTOM_SELECT_MISSING_REMOVE_TAGS_TEXTS]: string;
|
|
11
|
+
};
|
|
12
|
+
schema: never[];
|
|
13
|
+
};
|
|
14
|
+
create(context: any): any;
|
|
15
|
+
};
|
|
16
|
+
export default _default;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { defineTemplateBodyVisitor, getAttributeValue, isDBComponent } from '../../shared/utils.js';
|
|
2
|
+
import { COMPONENTS, MESSAGES, MESSAGE_IDS } from '../../shared/constants.js';
|
|
3
|
+
export default {
|
|
4
|
+
meta: {
|
|
5
|
+
type: 'problem',
|
|
6
|
+
docs: {
|
|
7
|
+
description: 'Ensure DBCustomSelect with selectedType="tag" has removeTagsTexts',
|
|
8
|
+
url: 'https://github.com/db-ux-design-system/core-web/blob/main/packages/eslint-plugin/README.md#custom-select-tags-remove-text-required'
|
|
9
|
+
},
|
|
10
|
+
messages: {
|
|
11
|
+
[MESSAGE_IDS.CUSTOM_SELECT_MISSING_REMOVE_TAGS_TEXTS]: MESSAGES.CUSTOM_SELECT_MISSING_REMOVE_TAGS_TEXTS
|
|
12
|
+
},
|
|
13
|
+
schema: []
|
|
14
|
+
},
|
|
15
|
+
create(context) {
|
|
16
|
+
const checkCustomSelect = (node) => {
|
|
17
|
+
const openingElement = node.openingElement || node;
|
|
18
|
+
if (!isDBComponent(openingElement, COMPONENTS.DBCustomSelect))
|
|
19
|
+
return;
|
|
20
|
+
const selectedType = getAttributeValue(openingElement, 'selectedType');
|
|
21
|
+
if (selectedType !== 'tag')
|
|
22
|
+
return;
|
|
23
|
+
const removeTagsTexts = getAttributeValue(openingElement, 'removeTagsTexts');
|
|
24
|
+
if (!removeTagsTexts) {
|
|
25
|
+
context.report({
|
|
26
|
+
node: openingElement,
|
|
27
|
+
messageId: MESSAGE_IDS.CUSTOM_SELECT_MISSING_REMOVE_TAGS_TEXTS
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
return defineTemplateBodyVisitor(context, { VElement: checkCustomSelect, Element: checkCustomSelect }, { JSXElement: checkCustomSelect });
|
|
32
|
+
}
|
|
33
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { MESSAGE_IDS } from '../../shared/constants.js';
|
|
2
|
+
declare const _default: {
|
|
3
|
+
meta: {
|
|
4
|
+
type: string;
|
|
5
|
+
docs: {
|
|
6
|
+
description: string;
|
|
7
|
+
url: string;
|
|
8
|
+
};
|
|
9
|
+
messages: {
|
|
10
|
+
[MESSAGE_IDS.SELECT_MISSING_OPTIONS]: string;
|
|
11
|
+
};
|
|
12
|
+
schema: never[];
|
|
13
|
+
};
|
|
14
|
+
create(context: any): any;
|
|
15
|
+
};
|
|
16
|
+
export default _default;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { defineTemplateBodyVisitor, getAttributeValue, isDBComponent } from '../../shared/utils.js';
|
|
2
|
+
import { COMPONENTS, MESSAGES, MESSAGE_IDS } from '../../shared/constants.js';
|
|
3
|
+
function hasOptionChildren(node) {
|
|
4
|
+
return node.children?.some((child) => {
|
|
5
|
+
if (child.type === 'JSXElement') {
|
|
6
|
+
const name = child.openingElement.name;
|
|
7
|
+
if (name.type === 'JSXIdentifier') {
|
|
8
|
+
return name.name === 'option';
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
if (child.type === 'VElement' || child.type === 'Element') {
|
|
12
|
+
return child.rawName === 'option' || child.name === 'option';
|
|
13
|
+
}
|
|
14
|
+
return false;
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
export default {
|
|
18
|
+
meta: {
|
|
19
|
+
type: 'problem',
|
|
20
|
+
docs: {
|
|
21
|
+
description: 'Ensure DBSelect has options property or option children',
|
|
22
|
+
url: 'https://github.com/db-ux-design-system/core-web/blob/main/packages/eslint-plugin/README.md#select-requires-options'
|
|
23
|
+
},
|
|
24
|
+
messages: {
|
|
25
|
+
[MESSAGE_IDS.SELECT_MISSING_OPTIONS]: MESSAGES.SELECT_MISSING_OPTIONS
|
|
26
|
+
},
|
|
27
|
+
schema: []
|
|
28
|
+
},
|
|
29
|
+
create(context) {
|
|
30
|
+
const checkSelect = (node) => {
|
|
31
|
+
const openingElement = node.openingElement || node;
|
|
32
|
+
if (!isDBComponent(openingElement, COMPONENTS.DBSelect))
|
|
33
|
+
return;
|
|
34
|
+
const options = getAttributeValue(openingElement, 'options');
|
|
35
|
+
const hasChildren = hasOptionChildren(node);
|
|
36
|
+
if (!options && !hasChildren) {
|
|
37
|
+
context.report({
|
|
38
|
+
node: openingElement,
|
|
39
|
+
messageId: MESSAGE_IDS.SELECT_MISSING_OPTIONS
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
return defineTemplateBodyVisitor(context, { VElement: checkSelect, Element: checkSelect }, { JSXElement: checkSelect });
|
|
44
|
+
}
|
|
45
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { MESSAGE_IDS } from '../../shared/constants.js';
|
|
2
|
+
declare const _default: {
|
|
3
|
+
meta: {
|
|
4
|
+
type: string;
|
|
5
|
+
docs: {
|
|
6
|
+
description: string;
|
|
7
|
+
url: string;
|
|
8
|
+
};
|
|
9
|
+
messages: {
|
|
10
|
+
[MESSAGE_IDS.TAG_REMOVABLE_REMOVE_BUTTON_REQUIRED]: string;
|
|
11
|
+
};
|
|
12
|
+
schema: never[];
|
|
13
|
+
};
|
|
14
|
+
create(context: any): any;
|
|
15
|
+
};
|
|
16
|
+
export default _default;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { createAngularVisitors, defineTemplateBodyVisitor, getAttributeValue, isDBComponent } from '../../shared/utils.js';
|
|
2
|
+
import { COMPONENTS, MESSAGES, MESSAGE_IDS } from '../../shared/constants.js';
|
|
3
|
+
export default {
|
|
4
|
+
meta: {
|
|
5
|
+
type: 'problem',
|
|
6
|
+
docs: {
|
|
7
|
+
description: 'Ensure DBTag with behavior="removable" has removeButton',
|
|
8
|
+
url: 'https://github.com/db-ux-design-system/core-web/blob/main/packages/eslint-plugin/README.md#tag-removable-remove-button-required'
|
|
9
|
+
},
|
|
10
|
+
messages: {
|
|
11
|
+
[MESSAGE_IDS.TAG_REMOVABLE_REMOVE_BUTTON_REQUIRED]: MESSAGES.TAG_REMOVABLE_REMOVE_BUTTON_REQUIRED
|
|
12
|
+
},
|
|
13
|
+
schema: []
|
|
14
|
+
},
|
|
15
|
+
create(context) {
|
|
16
|
+
const angularHandler = (node, parserServices) => {
|
|
17
|
+
const behavior = getAttributeValue(node, 'behavior');
|
|
18
|
+
if (behavior !== 'removable')
|
|
19
|
+
return;
|
|
20
|
+
const removeButton = getAttributeValue(node, 'removeButton');
|
|
21
|
+
if (!removeButton) {
|
|
22
|
+
const loc = parserServices.convertNodeSourceSpanToLoc(node.sourceSpan);
|
|
23
|
+
context.report({
|
|
24
|
+
loc,
|
|
25
|
+
messageId: MESSAGE_IDS.TAG_REMOVABLE_REMOVE_BUTTON_REQUIRED
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
const angularVisitors = createAngularVisitors(context, COMPONENTS.DBTag, angularHandler);
|
|
30
|
+
if (angularVisitors)
|
|
31
|
+
return angularVisitors;
|
|
32
|
+
const checkTag = (node) => {
|
|
33
|
+
const openingElement = node.openingElement || node;
|
|
34
|
+
if (!isDBComponent(openingElement, COMPONENTS.DBTag))
|
|
35
|
+
return;
|
|
36
|
+
const behavior = getAttributeValue(openingElement, 'behavior');
|
|
37
|
+
if (behavior !== 'removable')
|
|
38
|
+
return;
|
|
39
|
+
const removeButton = getAttributeValue(openingElement, 'removeButton');
|
|
40
|
+
if (!removeButton) {
|
|
41
|
+
context.report({
|
|
42
|
+
node: openingElement,
|
|
43
|
+
messageId: MESSAGE_IDS.TAG_REMOVABLE_REMOVE_BUTTON_REQUIRED
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
return defineTemplateBodyVisitor(context, { VElement: checkTag, Element: checkTag }, { JSXElement: checkTag });
|
|
48
|
+
}
|
|
49
|
+
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { defineTemplateBodyVisitor, isDBComponent } from '../../shared/utils.js';
|
|
2
|
+
import { INTERACTIVE_ELEMENTS } from '../../shared/constants.js';
|
|
3
|
+
function hasInteractiveChild(node) {
|
|
4
|
+
return node.children?.some((child) => {
|
|
5
|
+
if (child.type === 'JSXElement' || child.type === 'VElement') {
|
|
6
|
+
const openingElement = child.openingElement || child;
|
|
7
|
+
const name = openingElement.name || openingElement.rawName;
|
|
8
|
+
const tagName = typeof name === 'string'
|
|
9
|
+
? name
|
|
10
|
+
: name.type === 'JSXIdentifier'
|
|
11
|
+
? name.name
|
|
12
|
+
: null;
|
|
13
|
+
if (tagName &&
|
|
14
|
+
INTERACTIVE_ELEMENTS.some((el) => tagName === el ||
|
|
15
|
+
tagName === el.toLowerCase().replace('db', 'db-'))) {
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
return hasInteractiveChild(child);
|
|
19
|
+
}
|
|
20
|
+
return false;
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
export default {
|
|
24
|
+
meta: {
|
|
25
|
+
type: 'problem',
|
|
26
|
+
docs: {
|
|
27
|
+
description: 'Prevent interactive elements inside DBTooltip',
|
|
28
|
+
url: 'https://github.com/db-ux-design-system/core-web/blob/main/packages/eslint-plugin/README.md#no-interactive-tooltip-content'
|
|
29
|
+
},
|
|
30
|
+
messages: {
|
|
31
|
+
noInteractive: 'DBTooltip must not contain interactive elements. Use DBPopover for interactive content'
|
|
32
|
+
},
|
|
33
|
+
schema: []
|
|
34
|
+
},
|
|
35
|
+
create(context) {
|
|
36
|
+
const checkTooltip = (node) => {
|
|
37
|
+
const openingElement = node.openingElement || node;
|
|
38
|
+
if (!isDBComponent(openingElement, 'DBTooltip'))
|
|
39
|
+
return;
|
|
40
|
+
if (hasInteractiveChild(node)) {
|
|
41
|
+
context.report({
|
|
42
|
+
node: openingElement,
|
|
43
|
+
messageId: 'noInteractive'
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
return defineTemplateBodyVisitor(context, { VElement: checkTooltip, Element: checkTooltip }, { JSXElement: checkTooltip });
|
|
48
|
+
}
|
|
49
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { defineTemplateBodyVisitor, isDBComponent } from '../../shared/utils.js';
|
|
2
|
+
import { INTERACTIVE_ELEMENTS } from '../../shared/constants.js';
|
|
3
|
+
function isInteractiveElement(node) {
|
|
4
|
+
const openingElement = node.openingElement || node;
|
|
5
|
+
const tagName = openingElement.rawName ||
|
|
6
|
+
(openingElement.name?.type === 'JSXIdentifier'
|
|
7
|
+
? openingElement.name.name
|
|
8
|
+
: null);
|
|
9
|
+
if (!tagName)
|
|
10
|
+
return false;
|
|
11
|
+
return INTERACTIVE_ELEMENTS.some((el) => tagName === el || tagName === el.toLowerCase().replace('db', 'db-'));
|
|
12
|
+
}
|
|
13
|
+
export default {
|
|
14
|
+
meta: {
|
|
15
|
+
type: 'problem',
|
|
16
|
+
docs: {
|
|
17
|
+
description: 'Ensure DBTooltip is child of interactive element for accessibility',
|
|
18
|
+
url: 'https://github.com/db-ux-design-system/core-web/blob/main/packages/eslint-plugin/README.md#tooltip-requires-interactive-parent'
|
|
19
|
+
},
|
|
20
|
+
messages: {
|
|
21
|
+
requiresInteractive: 'DBTooltip must be a child of an interactive element (button, link, etc.) for accessibility'
|
|
22
|
+
},
|
|
23
|
+
schema: []
|
|
24
|
+
},
|
|
25
|
+
create(context) {
|
|
26
|
+
const checkTooltip = (node) => {
|
|
27
|
+
const openingElement = node.openingElement || node;
|
|
28
|
+
if (!isDBComponent(openingElement, 'DBTooltip'))
|
|
29
|
+
return;
|
|
30
|
+
let parent = node.parent;
|
|
31
|
+
while (parent) {
|
|
32
|
+
if (parent.type === 'JSXElement' ||
|
|
33
|
+
parent.type === 'VElement') {
|
|
34
|
+
if (isInteractiveElement(parent)) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
parent = parent.parent;
|
|
39
|
+
}
|
|
40
|
+
context.report({
|
|
41
|
+
node: openingElement,
|
|
42
|
+
messageId: 'requiresInteractive'
|
|
43
|
+
});
|
|
44
|
+
};
|
|
45
|
+
return defineTemplateBodyVisitor(context, { VElement: checkTooltip, Element: checkTooltip }, { JSXElement: checkTooltip });
|
|
46
|
+
}
|
|
47
|
+
};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
export declare const INTERACTIVE_ELEMENTS: string[];
|
|
2
|
+
export declare const COMPONENTS: Record<string, string>;
|
|
3
|
+
export declare const MESSAGES: {
|
|
4
|
+
BUTTON_TYPE_REQUIRED: string;
|
|
5
|
+
BUTTON_NO_TEXT_MISSING_ICON: string;
|
|
6
|
+
BUTTON_NO_TEXT_MISSING_TOOLTIP: string;
|
|
7
|
+
BUTTON_MULTIPLE_ICONS: string;
|
|
8
|
+
ACCORDION_NO_NESTED: string;
|
|
9
|
+
ACCORDION_ITEM_HEADLINE_REQUIRED: string;
|
|
10
|
+
BADGE_CORNER_TEXT_TOO_LONG: string;
|
|
11
|
+
BADGE_CORNER_MISSING_LABEL: string;
|
|
12
|
+
BADGE_NO_INLINE_IN_INTERACTIVE: string;
|
|
13
|
+
CLOSE_BUTTON_TEXT_REQUIRED: string;
|
|
14
|
+
TEXT_OR_CHILDREN_REQUIRED: string;
|
|
15
|
+
FORM_LABEL_REQUIRED: string;
|
|
16
|
+
FORM_VALIDATION_MESSAGE_REQUIRED: string;
|
|
17
|
+
TAG_REMOVABLE_REMOVE_BUTTON_REQUIRED: string;
|
|
18
|
+
INPUT_TYPE_REQUIRED: string;
|
|
19
|
+
INPUT_FILE_MISSING_ACCEPT: string;
|
|
20
|
+
INPUT_INVALID_MULTIPLE: string;
|
|
21
|
+
INPUT_INVALID_ACCEPT: string;
|
|
22
|
+
LINK_MISSING_TARGET_BLANK: string;
|
|
23
|
+
LINK_MISSING_REFERRER_POLICY: string;
|
|
24
|
+
LINK_MISSING_CONTENT_EXTERNAL: string;
|
|
25
|
+
NAVIGATION_ITEM_MISSING_BACK_BUTTON_TEXT: string;
|
|
26
|
+
SELECT_MISSING_OPTIONS: string;
|
|
27
|
+
CUSTOM_SELECT_MISSING_REMOVE_TAGS_TEXTS: string;
|
|
28
|
+
HEADER_MISSING_BURGER_MENU_LABEL: string;
|
|
29
|
+
ICON_PREFER_ATTRIBUTE: string;
|
|
30
|
+
};
|
|
31
|
+
export declare const MESSAGE_IDS: {
|
|
32
|
+
BUTTON_TYPE_REQUIRED: string;
|
|
33
|
+
BUTTON_NO_TEXT_MISSING_ICON: string;
|
|
34
|
+
BUTTON_NO_TEXT_MISSING_TOOLTIP: string;
|
|
35
|
+
BUTTON_MULTIPLE_ICONS: string;
|
|
36
|
+
ACCORDION_NO_NESTED: string;
|
|
37
|
+
ACCORDION_ITEM_HEADLINE_REQUIRED: string;
|
|
38
|
+
BADGE_CORNER_TEXT_TOO_LONG: string;
|
|
39
|
+
BADGE_CORNER_MISSING_LABEL: string;
|
|
40
|
+
BADGE_NO_INLINE_IN_INTERACTIVE: string;
|
|
41
|
+
CLOSE_BUTTON_TEXT_REQUIRED: string;
|
|
42
|
+
TEXT_OR_CHILDREN_REQUIRED: string;
|
|
43
|
+
FORM_LABEL_REQUIRED: string;
|
|
44
|
+
FORM_VALIDATION_MESSAGE_REQUIRED: string;
|
|
45
|
+
TAG_REMOVABLE_REMOVE_BUTTON_REQUIRED: string;
|
|
46
|
+
INPUT_TYPE_REQUIRED: string;
|
|
47
|
+
INPUT_FILE_MISSING_ACCEPT: string;
|
|
48
|
+
INPUT_INVALID_MULTIPLE: string;
|
|
49
|
+
INPUT_INVALID_ACCEPT: string;
|
|
50
|
+
LINK_MISSING_TARGET_BLANK: string;
|
|
51
|
+
LINK_MISSING_REFERRER_POLICY: string;
|
|
52
|
+
LINK_MISSING_CONTENT_EXTERNAL: string;
|
|
53
|
+
NAVIGATION_ITEM_MISSING_BACK_BUTTON_TEXT: string;
|
|
54
|
+
SELECT_MISSING_OPTIONS: string;
|
|
55
|
+
CUSTOM_SELECT_MISSING_REMOVE_TAGS_TEXTS: string;
|
|
56
|
+
HEADER_MISSING_BURGER_MENU_LABEL: string;
|
|
57
|
+
ICON_PREFER_ATTRIBUTE: string;
|
|
58
|
+
};
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
export const INTERACTIVE_ELEMENTS = [
|
|
2
|
+
'a',
|
|
3
|
+
'button',
|
|
4
|
+
'input',
|
|
5
|
+
'select',
|
|
6
|
+
'textarea',
|
|
7
|
+
'details',
|
|
8
|
+
'summary',
|
|
9
|
+
'DBButton',
|
|
10
|
+
'DBLink',
|
|
11
|
+
'DBInput',
|
|
12
|
+
'DBSelect',
|
|
13
|
+
'DBTextarea',
|
|
14
|
+
'DBCheckbox',
|
|
15
|
+
'DBRadio',
|
|
16
|
+
'DBSwitch',
|
|
17
|
+
'DBNavigationItem',
|
|
18
|
+
'DBTabItem',
|
|
19
|
+
'DBTag'
|
|
20
|
+
];
|
|
21
|
+
export const COMPONENTS = {
|
|
22
|
+
DBButton: 'DBButton',
|
|
23
|
+
DBInput: 'DBInput',
|
|
24
|
+
DBTextarea: 'DBTextarea',
|
|
25
|
+
DBSelect: 'DBSelect',
|
|
26
|
+
DBCustomSelect: 'DBCustomSelect',
|
|
27
|
+
DBCheckbox: 'DBCheckbox',
|
|
28
|
+
DBRadio: 'DBRadio',
|
|
29
|
+
DBSwitch: 'DBSwitch',
|
|
30
|
+
DBTooltip: 'DBTooltip',
|
|
31
|
+
DBIcon: 'DBIcon',
|
|
32
|
+
DBAccordion: 'DBAccordion',
|
|
33
|
+
DBAccordionItem: 'DBAccordionItem',
|
|
34
|
+
DBBadge: 'DBBadge',
|
|
35
|
+
DBLink: 'DBLink',
|
|
36
|
+
DBNotification: 'DBNotification',
|
|
37
|
+
DBDrawer: 'DBDrawer',
|
|
38
|
+
DBHeader: 'DBHeader',
|
|
39
|
+
DBNavigationItem: 'DBNavigationItem',
|
|
40
|
+
DBTag: 'DBTag',
|
|
41
|
+
DBTabItem: 'DBTabItem'
|
|
42
|
+
};
|
|
43
|
+
export const MESSAGES = {
|
|
44
|
+
BUTTON_TYPE_REQUIRED: 'DBButton must have an explicit type attribute (submit, button, or reset)',
|
|
45
|
+
BUTTON_NO_TEXT_MISSING_ICON: 'DBButton with noText must have an icon prop',
|
|
46
|
+
BUTTON_NO_TEXT_MISSING_TOOLTIP: 'DBButton with noText must have a DBTooltip child for accessibility',
|
|
47
|
+
BUTTON_MULTIPLE_ICONS: 'DBButton can only use one of: icon, iconLeading, or iconTrailing',
|
|
48
|
+
ACCORDION_NO_NESTED: 'DBAccordion must not be nested inside another DBAccordion as it confuses users',
|
|
49
|
+
ACCORDION_ITEM_HEADLINE_REQUIRED: 'DBAccordionItem must have either headline or headlinePlain attribute',
|
|
50
|
+
BADGE_CORNER_TEXT_TOO_LONG: 'DBBadge with corner placement must have max 3 characters in text/children',
|
|
51
|
+
BADGE_CORNER_MISSING_LABEL: 'DBBadge with corner placement must have a label attribute for accessibility',
|
|
52
|
+
BADGE_NO_INLINE_IN_INTERACTIVE: 'DBBadge inside {{parent}} cannot have placement="inline". Use corner placement instead',
|
|
53
|
+
CLOSE_BUTTON_TEXT_REQUIRED: '{{component}} must have {{attribute}} attribute for accessibility',
|
|
54
|
+
TEXT_OR_CHILDREN_REQUIRED: '{{component}} must have either a text property or children content',
|
|
55
|
+
FORM_LABEL_REQUIRED: '{{component}} must have a label attribute for accessibility',
|
|
56
|
+
FORM_VALIDATION_MESSAGE_REQUIRED: '{{component}} with {{attribute}} will use default browser validation message. Consider adding invalidMessage attribute for better UX',
|
|
57
|
+
TAG_REMOVABLE_REMOVE_BUTTON_REQUIRED: 'DBTag with behavior="removable" must have removeButton attribute for accessibility',
|
|
58
|
+
INPUT_TYPE_REQUIRED: 'DBInput should have type attribute for better developer experience',
|
|
59
|
+
INPUT_FILE_MISSING_ACCEPT: 'DBInput with type="file" should have accept attribute',
|
|
60
|
+
INPUT_INVALID_MULTIPLE: 'DBInput multiple attribute is only valid for type="file"',
|
|
61
|
+
INPUT_INVALID_ACCEPT: 'DBInput accept attribute is only valid for type="file"',
|
|
62
|
+
LINK_MISSING_TARGET_BLANK: 'DBLink with content="external" should have target="_blank"',
|
|
63
|
+
LINK_MISSING_REFERRER_POLICY: 'DBLink with content="external" should have referrerPolicy attribute',
|
|
64
|
+
LINK_MISSING_CONTENT_EXTERNAL: 'DBLink with target="_blank" should have content="external"',
|
|
65
|
+
NAVIGATION_ITEM_MISSING_BACK_BUTTON_TEXT: 'DBNavigationItem must have backButtonText attribute for accessibility',
|
|
66
|
+
SELECT_MISSING_OPTIONS: 'DBSelect must have either an options property or <option> children',
|
|
67
|
+
CUSTOM_SELECT_MISSING_REMOVE_TAGS_TEXTS: 'DBCustomSelect with selectedType="tag" must have removeTagsTexts attribute for accessibility',
|
|
68
|
+
HEADER_MISSING_BURGER_MENU_LABEL: 'DBHeader must have burgerMenuLabel attribute for accessibility',
|
|
69
|
+
ICON_PREFER_ATTRIBUTE: 'Use icon attribute instead of DBIcon child in {{component}}'
|
|
70
|
+
};
|
|
71
|
+
export const MESSAGE_IDS = {
|
|
72
|
+
BUTTON_TYPE_REQUIRED: 'missingType',
|
|
73
|
+
BUTTON_NO_TEXT_MISSING_ICON: 'missingIcon',
|
|
74
|
+
BUTTON_NO_TEXT_MISSING_TOOLTIP: 'missingTooltip',
|
|
75
|
+
BUTTON_MULTIPLE_ICONS: 'multipleIcons',
|
|
76
|
+
ACCORDION_NO_NESTED: 'noNested',
|
|
77
|
+
ACCORDION_ITEM_HEADLINE_REQUIRED: 'headlineRequired',
|
|
78
|
+
BADGE_CORNER_TEXT_TOO_LONG: 'textTooLong',
|
|
79
|
+
BADGE_CORNER_MISSING_LABEL: 'missingLabel',
|
|
80
|
+
BADGE_NO_INLINE_IN_INTERACTIVE: 'noInline',
|
|
81
|
+
CLOSE_BUTTON_TEXT_REQUIRED: 'missingCloseButtonText',
|
|
82
|
+
TEXT_OR_CHILDREN_REQUIRED: 'missingContent',
|
|
83
|
+
FORM_LABEL_REQUIRED: 'missingLabel',
|
|
84
|
+
FORM_VALIDATION_MESSAGE_REQUIRED: 'missingInvalidMessage',
|
|
85
|
+
TAG_REMOVABLE_REMOVE_BUTTON_REQUIRED: 'missingRemoveButton',
|
|
86
|
+
INPUT_TYPE_REQUIRED: 'missingType',
|
|
87
|
+
INPUT_FILE_MISSING_ACCEPT: 'missingAccept',
|
|
88
|
+
INPUT_INVALID_MULTIPLE: 'invalidMultiple',
|
|
89
|
+
INPUT_INVALID_ACCEPT: 'invalidAccept',
|
|
90
|
+
LINK_MISSING_TARGET_BLANK: 'missingTargetBlank',
|
|
91
|
+
LINK_MISSING_REFERRER_POLICY: 'missingReferrerPolicy',
|
|
92
|
+
LINK_MISSING_CONTENT_EXTERNAL: 'missingContentExternal',
|
|
93
|
+
NAVIGATION_ITEM_MISSING_BACK_BUTTON_TEXT: 'missingBackButtonText',
|
|
94
|
+
SELECT_MISSING_OPTIONS: 'missingOptions',
|
|
95
|
+
CUSTOM_SELECT_MISSING_REMOVE_TAGS_TEXTS: 'missingRemoveTagsTexts',
|
|
96
|
+
HEADER_MISSING_BURGER_MENU_LABEL: 'missingBurgerMenuLabel',
|
|
97
|
+
ICON_PREFER_ATTRIBUTE: 'preferAttribute'
|
|
98
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { TSESTree } from '@typescript-eslint/utils';
|
|
2
|
+
type VElement = {
|
|
3
|
+
type: 'VElement';
|
|
4
|
+
startTag: {
|
|
5
|
+
attributes: Array<{
|
|
6
|
+
key: {
|
|
7
|
+
name: string;
|
|
8
|
+
argument?: {
|
|
9
|
+
name: string;
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
value?: {
|
|
13
|
+
value: string;
|
|
14
|
+
};
|
|
15
|
+
}>;
|
|
16
|
+
range: [number, number];
|
|
17
|
+
};
|
|
18
|
+
rawName: string;
|
|
19
|
+
children?: VElement[];
|
|
20
|
+
range: [number, number];
|
|
21
|
+
};
|
|
22
|
+
type AngularElement = {
|
|
23
|
+
type?: string;
|
|
24
|
+
name: string;
|
|
25
|
+
attributes: Array<{
|
|
26
|
+
name: string;
|
|
27
|
+
value?: string;
|
|
28
|
+
}>;
|
|
29
|
+
inputs: Array<{
|
|
30
|
+
name: string;
|
|
31
|
+
value?: any;
|
|
32
|
+
}>;
|
|
33
|
+
outputs: Array<{
|
|
34
|
+
name: string;
|
|
35
|
+
}>;
|
|
36
|
+
children?: AngularElement[];
|
|
37
|
+
};
|
|
38
|
+
type ElementNode = TSESTree.JSXOpeningElement | VElement | AngularElement;
|
|
39
|
+
export declare function getAttributeValue(node: ElementNode, attrName: string): string | boolean | null;
|
|
40
|
+
export declare function hasChildOfType(node: TSESTree.JSXElement | VElement | AngularElement, componentName: string): boolean;
|
|
41
|
+
export declare function isDBComponent(node: ElementNode, componentName: string): boolean;
|
|
42
|
+
export declare function defineTemplateBodyVisitor(context: any, templateVisitor: any, scriptVisitor?: any): any;
|
|
43
|
+
export declare function createAngularVisitors(context: any, componentName: string, handler: (node: any, parserServices: any) => void): {
|
|
44
|
+
[x: string]: (node: any) => void;
|
|
45
|
+
} | null;
|
|
46
|
+
export declare function createAngularFix(context: any, node: any, attributeText: string): {
|
|
47
|
+
insertPos: any;
|
|
48
|
+
attributeText: string;
|
|
49
|
+
} | null;
|
|
50
|
+
export declare function createJsxVueFix(node: any, openingElement: any, attributeText: string): {
|
|
51
|
+
insertPos: any;
|
|
52
|
+
attributeText: string;
|
|
53
|
+
};
|
|
54
|
+
export {};
|