@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.
Files changed (53) hide show
  1. package/CHANGELOG.md +1 -0
  2. package/README.md +843 -0
  3. package/build/index.d.ts +352 -0
  4. package/build/index.js +82 -0
  5. package/build/rules/accordion/accordion-item-headline-required.d.ts +16 -0
  6. package/build/rules/accordion/accordion-item-headline-required.js +61 -0
  7. package/build/rules/accordion/no-nested-accordion.d.ts +16 -0
  8. package/build/rules/accordion/no-nested-accordion.js +54 -0
  9. package/build/rules/badge/badge-corner-placement-rules.d.ts +18 -0
  10. package/build/rules/badge/badge-corner-placement-rules.js +114 -0
  11. package/build/rules/badge/badge-no-inline-in-interactive.d.ts +17 -0
  12. package/build/rules/badge/badge-no-inline-in-interactive.js +129 -0
  13. package/build/rules/button/button-no-text-requires-tooltip.d.ts +18 -0
  14. package/build/rules/button/button-no-text-requires-tooltip.js +109 -0
  15. package/build/rules/button/button-single-icon-attribute.d.ts +16 -0
  16. package/build/rules/button/button-single-icon-attribute.js +49 -0
  17. package/build/rules/button/button-type-required.d.ts +17 -0
  18. package/build/rules/button/button-type-required.js +58 -0
  19. package/build/rules/close-button/close-button-text-required.d.ts +16 -0
  20. package/build/rules/close-button/close-button-text-required.js +38 -0
  21. package/build/rules/content/text-or-children-required.d.ts +16 -0
  22. package/build/rules/content/text-or-children-required.js +47 -0
  23. package/build/rules/form/form-label-required.d.ts +16 -0
  24. package/build/rules/form/form-label-required.js +45 -0
  25. package/build/rules/form/form-validation-message-required.d.ts +16 -0
  26. package/build/rules/form/form-validation-message-required.js +91 -0
  27. package/build/rules/header/header-burger-menu-label-required.d.ts +16 -0
  28. package/build/rules/header/header-burger-menu-label-required.js +43 -0
  29. package/build/rules/icon/prefer-icon-attribute.d.ts +17 -0
  30. package/build/rules/icon/prefer-icon-attribute.js +82 -0
  31. package/build/rules/input/input-file-type-validation.d.ts +18 -0
  32. package/build/rules/input/input-file-type-validation.js +50 -0
  33. package/build/rules/input/input-type-required.d.ts +17 -0
  34. package/build/rules/input/input-type-required.js +54 -0
  35. package/build/rules/link/link-external-security.d.ts +19 -0
  36. package/build/rules/link/link-external-security.js +166 -0
  37. package/build/rules/navigation/navigation-item-back-button-text-required.d.ts +16 -0
  38. package/build/rules/navigation/navigation-item-back-button-text-required.js +43 -0
  39. package/build/rules/select/custom-select-tags-remove-text-required.d.ts +16 -0
  40. package/build/rules/select/custom-select-tags-remove-text-required.js +33 -0
  41. package/build/rules/select/select-requires-options.d.ts +16 -0
  42. package/build/rules/select/select-requires-options.js +45 -0
  43. package/build/rules/tag/tag-removable-remove-button-required.d.ts +16 -0
  44. package/build/rules/tag/tag-removable-remove-button-required.js +49 -0
  45. package/build/rules/tooltip/no-interactive-tooltip-content.d.ts +15 -0
  46. package/build/rules/tooltip/no-interactive-tooltip-content.js +49 -0
  47. package/build/rules/tooltip/tooltip-requires-interactive-parent.d.ts +15 -0
  48. package/build/rules/tooltip/tooltip-requires-interactive-parent.js +47 -0
  49. package/build/shared/constants.d.ts +58 -0
  50. package/build/shared/constants.js +98 -0
  51. package/build/shared/utils.d.ts +54 -0
  52. package/build/shared/utils.js +178 -0
  53. package/package.json +37 -1
@@ -0,0 +1,178 @@
1
+ function isVElement(node) {
2
+ return node.type === 'VElement';
3
+ }
4
+ function isAngularElement(node) {
5
+ return (node &&
6
+ typeof node.name === 'string' &&
7
+ (node.attributes || node.inputs));
8
+ }
9
+ export function getAttributeValue(node, attrName) {
10
+ const kebabAttrName = attrName
11
+ .replace(/([a-z])([A-Z])/g, '$1-$2')
12
+ .toLowerCase();
13
+ if (isAngularElement(node)) {
14
+ const attr = node.attributes.find((a) => a.name === attrName || a.name === kebabAttrName);
15
+ if (attr) {
16
+ return attr.value === undefined || attr.value === ''
17
+ ? true
18
+ : attr.value;
19
+ }
20
+ const input = node.inputs.find((i) => i.name === attrName || i.name === kebabAttrName);
21
+ if (input)
22
+ return true;
23
+ return null;
24
+ }
25
+ if (isVElement(node)) {
26
+ const attr = node.startTag.attributes.find((a) => {
27
+ if (a.key.name === 'bind' && a.key.argument?.name === attrName)
28
+ return true;
29
+ return (a.key.name === attrName ||
30
+ a.key.name === kebabAttrName ||
31
+ a.key.name === `:${attrName}` ||
32
+ a.key.name === `:${kebabAttrName}`);
33
+ });
34
+ if (!attr)
35
+ return null;
36
+ if (!attr.value)
37
+ return true;
38
+ return attr.value.value;
39
+ }
40
+ const variants = [attrName, `[${attrName}]`, `:${attrName}`];
41
+ const attr = node.attributes.find((a) => a.type === 'JSXAttribute' &&
42
+ variants.includes(a.name.name));
43
+ if (!attr)
44
+ return null;
45
+ if (!attr.value)
46
+ return true;
47
+ if (attr.value.type === 'Literal')
48
+ return attr.value.value;
49
+ if (attr.value.type === 'JSXExpressionContainer')
50
+ return true;
51
+ return null;
52
+ }
53
+ export function hasChildOfType(node, componentName) {
54
+ const kebabName = componentName
55
+ .replace(/([a-z])([A-Z])/g, '$1-$2')
56
+ .toLowerCase();
57
+ if (isAngularElement(node)) {
58
+ return (node.children || []).some((child) => {
59
+ if (child.type === 'Element') {
60
+ return child.name === componentName || child.name === kebabName;
61
+ }
62
+ return false;
63
+ });
64
+ }
65
+ if (isVElement(node)) {
66
+ return (node.children || []).some((child) => {
67
+ if (child.type === 'VElement') {
68
+ return (child.rawName === componentName ||
69
+ child.rawName === kebabName);
70
+ }
71
+ return false;
72
+ });
73
+ }
74
+ return node.children.some((child) => {
75
+ if (child.type === 'JSXElement') {
76
+ const openingElement = child.openingElement;
77
+ if (openingElement.name.type === 'JSXIdentifier') {
78
+ const name = openingElement.name.name;
79
+ return name === componentName || name === kebabName;
80
+ }
81
+ }
82
+ return false;
83
+ });
84
+ }
85
+ export function isDBComponent(node, componentName) {
86
+ const kebabName = componentName
87
+ .replace(/([a-z])([A-Z])/g, '$1-$2')
88
+ .toLowerCase();
89
+ if (isAngularElement(node)) {
90
+ return node.name === componentName || node.name === kebabName;
91
+ }
92
+ if (isVElement(node)) {
93
+ return node.rawName === componentName || node.rawName === kebabName;
94
+ }
95
+ if (node.name.type !== 'JSXIdentifier')
96
+ return false;
97
+ const name = node.name.name;
98
+ return name === componentName || name === kebabName;
99
+ }
100
+ export function defineTemplateBodyVisitor(context, templateVisitor, scriptVisitor) {
101
+ const sourceCode = context.sourceCode || context.getSourceCode();
102
+ // Vue templates
103
+ if (sourceCode.parserServices?.defineTemplateBodyVisitor) {
104
+ return sourceCode.parserServices.defineTemplateBodyVisitor(templateVisitor, scriptVisitor || {});
105
+ }
106
+ // Angular templates
107
+ if (sourceCode.parserServices?.convertNodeSourceSpanToLoc) {
108
+ const angularVisitors = {};
109
+ for (const [key, handler] of Object.entries(templateVisitor)) {
110
+ if (key === 'VElement' || key === 'Element') {
111
+ angularVisitors['Element'] = handler;
112
+ }
113
+ else {
114
+ angularVisitors[key] = handler;
115
+ }
116
+ }
117
+ return angularVisitors;
118
+ }
119
+ // JSX
120
+ return scriptVisitor || {};
121
+ }
122
+ export function createAngularVisitors(context, componentName, handler) {
123
+ const sourceCode = context.sourceCode || context.getSourceCode();
124
+ const parserServices = sourceCode?.parserServices;
125
+ const isAngular = parserServices?.convertNodeSourceSpanToLoc;
126
+ if (!isAngular) {
127
+ return null;
128
+ }
129
+ // For DB components, convert DBComponentName -> db-component-name
130
+ const kebabName = componentName.startsWith('DB')
131
+ ? 'db-' +
132
+ componentName
133
+ .slice(2)
134
+ .replace(/([a-z])([A-Z])/g, '$1-$2')
135
+ .toLowerCase()
136
+ : componentName.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
137
+ const wrappedHandler = (node) => handler(node, parserServices);
138
+ return {
139
+ [`Element[name="${kebabName}"]`]: wrappedHandler,
140
+ [`Element[name="${componentName}"]`]: wrappedHandler
141
+ };
142
+ }
143
+ export function createAngularFix(context, node, attributeText) {
144
+ const sourceCode = context.sourceCode || context.getSourceCode();
145
+ const text = sourceCode.getText();
146
+ const startOffset = node.sourceSpan.start.offset;
147
+ const endOffset = node.sourceSpan.end.offset;
148
+ const tagText = text.substring(startOffset, endOffset);
149
+ const closeTagIndex = tagText.indexOf('>');
150
+ if (closeTagIndex === -1)
151
+ return null;
152
+ const insertPos = startOffset + closeTagIndex;
153
+ return { insertPos, attributeText };
154
+ }
155
+ export function createJsxVueFix(node, openingElement, attributeText) {
156
+ if (node.openingElement) {
157
+ // JSX
158
+ const lastAttr = openingElement.attributes[openingElement.attributes.length - 1];
159
+ const insertPos = lastAttr
160
+ ? lastAttr.range[1]
161
+ : openingElement.name.range[1];
162
+ return { insertPos, attributeText };
163
+ }
164
+ else {
165
+ // Vue
166
+ const attrs = openingElement.startTag.attributes;
167
+ if (attrs.length > 0) {
168
+ const lastAttr = attrs[attrs.length - 1];
169
+ return { insertPos: lastAttr.range[1], attributeText };
170
+ }
171
+ else {
172
+ const insertPos = openingElement.startTag.range[0] +
173
+ 1 +
174
+ openingElement.rawName.length;
175
+ return { insertPos, attributeText };
176
+ }
177
+ }
178
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@db-ux/core-eslint-plugin",
3
- "version": "0.0.0",
3
+ "version": "4.4.2-eslint-plugin2-696cb23",
4
4
  "type": "module",
5
5
  "description": "ESLint plugin for DB UX Design System components",
6
6
  "repository": {
@@ -8,11 +8,47 @@
8
8
  "url": "git+https://github.com/db-ux-design-system/core-web.git"
9
9
  },
10
10
  "license": "Apache-2.0",
11
+ "exports": {
12
+ ".": {
13
+ "types": "./build/index.d.ts",
14
+ "default": "./build/index.js"
15
+ }
16
+ },
17
+ "files": [
18
+ "CHANGELOG.md",
19
+ "build"
20
+ ],
11
21
  "keywords": [
12
22
  "eslint",
13
23
  "eslint-plugin",
14
24
  "db-ux"
15
25
  ],
26
+ "scripts": {
27
+ "build": "tsc",
28
+ "copy-output": "npm-run-all copy:*",
29
+ "copy:changelog": "cpr CHANGELOG.md ../../build-outputs/eslint-plugin/CHANGELOG.md --overwrite",
30
+ "copy:outputs": "cpr build ../../build-outputs/eslint-plugin/build -o",
31
+ "copy:package.json": "cpr package.json ../../build-outputs/eslint-plugin/package.json -o",
32
+ "copy:readme": "cpr README.md ../../build-outputs/eslint-plugin/README.md -o",
33
+ "test": "vitest run --config vitest.config.ts",
34
+ "test:update": "vitest run --config vitest.config.ts --update"
35
+ },
36
+ "peerDependencies": {
37
+ "eslint": "^9.0.0 || ^10.0.0"
38
+ },
39
+ "dependencies": {
40
+ "@angular-eslint/utils": "20.7.0",
41
+ "@typescript-eslint/utils": "8.54.0"
42
+ },
43
+ "devDependencies": {
44
+ "@angular-eslint/bundled-angular-compiler": "20.7.0",
45
+ "@angular-eslint/template-parser": "20.3.0",
46
+ "@typescript-eslint/parser": "8.54.0",
47
+ "@typescript-eslint/rule-tester": "8.54.0",
48
+ "typescript": "5.9.3",
49
+ "vitest": "3.2.4",
50
+ "vue-eslint-parser": "9.4.3"
51
+ },
16
52
  "publishConfig": {
17
53
  "registry": "https://registry.npmjs.org/",
18
54
  "access": "public"