@atlaskit/eslint-plugin-design-system 13.8.0 → 13.10.0
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 +16 -0
- package/README.md +2 -0
- package/dist/cjs/presets/all-flat.codegen.js +3 -1
- package/dist/cjs/presets/all.codegen.js +3 -1
- package/dist/cjs/presets/recommended-flat.codegen.js +3 -1
- package/dist/cjs/presets/recommended.codegen.js +3 -1
- package/dist/cjs/rules/index.codegen.js +5 -1
- package/dist/cjs/rules/no-html-heading/index.js +40 -0
- package/dist/cjs/rules/no-html-heading/node-types/index.js +19 -0
- package/dist/cjs/rules/no-html-heading/node-types/jsx-element/index.js +136 -0
- package/dist/cjs/rules/no-html-heading/node-types/styled-component/index.js +42 -0
- package/dist/cjs/rules/no-html-heading/node-types/supported.js +82 -0
- package/dist/cjs/rules/no-html-select/index.js +40 -0
- package/dist/cjs/rules/no-html-select/node-types/index.js +19 -0
- package/dist/cjs/rules/no-html-select/node-types/jsx-element/index.js +27 -0
- package/dist/cjs/rules/no-html-select/node-types/styled-component/index.js +42 -0
- package/dist/cjs/rules/no-html-select/node-types/supported.js +66 -0
- package/dist/es2019/presets/all-flat.codegen.js +3 -1
- package/dist/es2019/presets/all.codegen.js +3 -1
- package/dist/es2019/presets/recommended-flat.codegen.js +3 -1
- package/dist/es2019/presets/recommended.codegen.js +3 -1
- package/dist/es2019/rules/index.codegen.js +5 -1
- package/dist/es2019/rules/no-html-heading/index.js +34 -0
- package/dist/es2019/rules/no-html-heading/node-types/index.js +2 -0
- package/dist/es2019/rules/no-html-heading/node-types/jsx-element/index.js +99 -0
- package/dist/es2019/rules/no-html-heading/node-types/styled-component/index.js +37 -0
- package/dist/es2019/rules/no-html-heading/node-types/supported.js +72 -0
- package/dist/es2019/rules/no-html-select/index.js +34 -0
- package/dist/es2019/rules/no-html-select/node-types/index.js +2 -0
- package/dist/es2019/rules/no-html-select/node-types/jsx-element/index.js +19 -0
- package/dist/es2019/rules/no-html-select/node-types/styled-component/index.js +37 -0
- package/dist/es2019/rules/no-html-select/node-types/supported.js +56 -0
- package/dist/esm/presets/all-flat.codegen.js +3 -1
- package/dist/esm/presets/all.codegen.js +3 -1
- package/dist/esm/presets/recommended-flat.codegen.js +3 -1
- package/dist/esm/presets/recommended.codegen.js +3 -1
- package/dist/esm/rules/index.codegen.js +5 -1
- package/dist/esm/rules/no-html-heading/index.js +34 -0
- package/dist/esm/rules/no-html-heading/node-types/index.js +2 -0
- package/dist/esm/rules/no-html-heading/node-types/jsx-element/index.js +127 -0
- package/dist/esm/rules/no-html-heading/node-types/styled-component/index.js +36 -0
- package/dist/esm/rules/no-html-heading/node-types/supported.js +73 -0
- package/dist/esm/rules/no-html-select/index.js +34 -0
- package/dist/esm/rules/no-html-select/node-types/index.js +2 -0
- package/dist/esm/rules/no-html-select/node-types/jsx-element/index.js +18 -0
- package/dist/esm/rules/no-html-select/node-types/styled-component/index.js +36 -0
- package/dist/esm/rules/no-html-select/node-types/supported.js +57 -0
- package/dist/types/index.codegen.d.ts +18 -0
- package/dist/types/presets/all-flat.codegen.d.ts +2 -0
- package/dist/types/presets/all.codegen.d.ts +2 -0
- package/dist/types/presets/recommended-flat.codegen.d.ts +2 -0
- package/dist/types/presets/recommended.codegen.d.ts +2 -0
- package/dist/types/rules/index.codegen.d.ts +2 -0
- package/dist/types/rules/no-html-heading/index.d.ts +3 -0
- package/dist/types/rules/no-html-heading/node-types/index.d.ts +2 -0
- package/dist/types/rules/no-html-heading/node-types/jsx-element/index.d.ts +8 -0
- package/dist/types/rules/no-html-heading/node-types/styled-component/index.d.ts +8 -0
- package/dist/types/rules/no-html-heading/node-types/supported.d.ts +7 -0
- package/dist/types/rules/no-html-select/index.d.ts +3 -0
- package/dist/types/rules/no-html-select/node-types/index.d.ts +2 -0
- package/dist/types/rules/no-html-select/node-types/jsx-element/index.d.ts +8 -0
- package/dist/types/rules/no-html-select/node-types/styled-component/index.d.ts +8 -0
- package/dist/types/rules/no-html-select/node-types/supported.d.ts +7 -0
- package/dist/types-ts4.5/index.codegen.d.ts +18 -0
- package/dist/types-ts4.5/presets/all-flat.codegen.d.ts +2 -0
- package/dist/types-ts4.5/presets/all.codegen.d.ts +2 -0
- package/dist/types-ts4.5/presets/recommended-flat.codegen.d.ts +2 -0
- package/dist/types-ts4.5/presets/recommended.codegen.d.ts +2 -0
- package/dist/types-ts4.5/rules/index.codegen.d.ts +2 -0
- package/dist/types-ts4.5/rules/no-html-heading/index.d.ts +3 -0
- package/dist/types-ts4.5/rules/no-html-heading/node-types/index.d.ts +2 -0
- package/dist/types-ts4.5/rules/no-html-heading/node-types/jsx-element/index.d.ts +8 -0
- package/dist/types-ts4.5/rules/no-html-heading/node-types/styled-component/index.d.ts +8 -0
- package/dist/types-ts4.5/rules/no-html-heading/node-types/supported.d.ts +7 -0
- package/dist/types-ts4.5/rules/no-html-select/index.d.ts +3 -0
- package/dist/types-ts4.5/rules/no-html-select/node-types/index.d.ts +2 -0
- package/dist/types-ts4.5/rules/no-html-select/node-types/jsx-element/index.d.ts +8 -0
- package/dist/types-ts4.5/rules/no-html-select/node-types/styled-component/index.d.ts +8 -0
- package/dist/types-ts4.5/rules/no-html-select/node-types/supported.d.ts +7 -0
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* THIS FILE WAS CREATED VIA CODEGEN DO NOT MODIFY {@see http://go/af-codegen}
|
|
3
|
-
* @codegen <<SignedSource::
|
|
3
|
+
* @codegen <<SignedSource::19fc297469c40b1fa9fd64c9f9313ba7>>
|
|
4
4
|
* @codegenCommand yarn workspace @atlaskit/eslint-plugin-design-system codegen
|
|
5
5
|
*/
|
|
6
6
|
import consistentCssPropUsage from './consistent-css-prop-usage';
|
|
@@ -23,8 +23,10 @@ import noExportedKeyframes from './no-exported-keyframes';
|
|
|
23
23
|
import noHtmlAnchor from './no-html-anchor';
|
|
24
24
|
import noHtmlButton from './no-html-button';
|
|
25
25
|
import noHtmlCheckbox from './no-html-checkbox';
|
|
26
|
+
import noHtmlHeading from './no-html-heading';
|
|
26
27
|
import noHtmlImage from './no-html-image';
|
|
27
28
|
import noHtmlRange from './no-html-range';
|
|
29
|
+
import noHtmlSelect from './no-html-select';
|
|
28
30
|
import noInvalidCssMap from './no-invalid-css-map';
|
|
29
31
|
import noKeyframesTaggedTemplateExpression from './no-keyframes-tagged-template-expression';
|
|
30
32
|
import noLegacyIcons from './no-legacy-icons';
|
|
@@ -78,8 +80,10 @@ export var rules = {
|
|
|
78
80
|
'no-html-anchor': noHtmlAnchor,
|
|
79
81
|
'no-html-button': noHtmlButton,
|
|
80
82
|
'no-html-checkbox': noHtmlCheckbox,
|
|
83
|
+
'no-html-heading': noHtmlHeading,
|
|
81
84
|
'no-html-image': noHtmlImage,
|
|
82
85
|
'no-html-range': noHtmlRange,
|
|
86
|
+
'no-html-select': noHtmlSelect,
|
|
83
87
|
'no-invalid-css-map': noInvalidCssMap,
|
|
84
88
|
'no-keyframes-tagged-template-expression': noKeyframesTaggedTemplateExpression,
|
|
85
89
|
'no-legacy-icons': noLegacyIcons,
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { createLintRule } from '../utils/create-rule';
|
|
2
|
+
import { JSXElement as _JSXElement, StyledComponent } from './node-types';
|
|
3
|
+
var rule = createLintRule({
|
|
4
|
+
meta: {
|
|
5
|
+
name: 'no-html-heading',
|
|
6
|
+
type: 'suggestion',
|
|
7
|
+
hasSuggestions: true,
|
|
8
|
+
docs: {
|
|
9
|
+
description: 'Discourage direct usage of HTML heading elements in favor of Atlassian Design System heading components.',
|
|
10
|
+
recommended: true,
|
|
11
|
+
severity: 'warn'
|
|
12
|
+
},
|
|
13
|
+
messages: {
|
|
14
|
+
noHtmlHeading: "This <{{ name }}> should be replaced with a heading component from the Atlassian Design System. ADS headings include ensure accessible implementations and provide access to ADS styling features like design tokens."
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
create: function create(context) {
|
|
18
|
+
return {
|
|
19
|
+
// transforms styled.<heading>(...) usages
|
|
20
|
+
CallExpression: function CallExpression(node) {
|
|
21
|
+
StyledComponent.lint(node, {
|
|
22
|
+
context: context
|
|
23
|
+
});
|
|
24
|
+
},
|
|
25
|
+
// transforms <heading css={...}> usages
|
|
26
|
+
JSXElement: function JSXElement(node) {
|
|
27
|
+
_JSXElement.lint(node, {
|
|
28
|
+
context: context
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
export default rule;
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
|
|
2
|
+
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
|
|
3
|
+
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
|
|
4
|
+
import { isNodeOfType } from 'eslint-codemod-utils';
|
|
5
|
+
import { getSourceCode } from '@atlaskit/eslint-utils/context-compat';
|
|
6
|
+
import * as ast from '../../../../ast-nodes';
|
|
7
|
+
import { isSupportedForLint } from '../supported';
|
|
8
|
+
function isImportDeclaration(node) {
|
|
9
|
+
return node.type === 'ImportDeclaration';
|
|
10
|
+
}
|
|
11
|
+
export var JSXElement = {
|
|
12
|
+
lint: function lint(node, _ref) {
|
|
13
|
+
var context = _ref.context;
|
|
14
|
+
if (!isSupportedForLint(node)) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
var nodeName = ast.JSXElement.getName(node);
|
|
18
|
+
var sourceCode = getSourceCode(context);
|
|
19
|
+
var importDeclarations = sourceCode.ast.body.filter(isImportDeclaration);
|
|
20
|
+
var existingHeadingName = null;
|
|
21
|
+
var usedNames = new Set();
|
|
22
|
+
|
|
23
|
+
// Check for existing imports
|
|
24
|
+
var _iterator = _createForOfIteratorHelper(importDeclarations),
|
|
25
|
+
_step;
|
|
26
|
+
try {
|
|
27
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
28
|
+
var declaration = _step.value;
|
|
29
|
+
var _iterator2 = _createForOfIteratorHelper(declaration.specifiers),
|
|
30
|
+
_step2;
|
|
31
|
+
try {
|
|
32
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
33
|
+
var specifier = _step2.value;
|
|
34
|
+
usedNames.add(specifier.local.name);
|
|
35
|
+
}
|
|
36
|
+
} catch (err) {
|
|
37
|
+
_iterator2.e(err);
|
|
38
|
+
} finally {
|
|
39
|
+
_iterator2.f();
|
|
40
|
+
}
|
|
41
|
+
if (declaration.source.value === '@atlaskit/heading') {
|
|
42
|
+
var defaultSpecifier = declaration.specifiers.find(function (specifier) {
|
|
43
|
+
return specifier.type === 'ImportDefaultSpecifier';
|
|
44
|
+
});
|
|
45
|
+
if (defaultSpecifier) {
|
|
46
|
+
existingHeadingName = defaultSpecifier.local.name;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
} catch (err) {
|
|
51
|
+
_iterator.e(err);
|
|
52
|
+
} finally {
|
|
53
|
+
_iterator.f();
|
|
54
|
+
}
|
|
55
|
+
var generateUniqueName = function generateUniqueName(baseName) {
|
|
56
|
+
var index = 1;
|
|
57
|
+
var newName = baseName;
|
|
58
|
+
while (usedNames.has(newName)) {
|
|
59
|
+
newName = "".concat(baseName).concat(index);
|
|
60
|
+
index++;
|
|
61
|
+
}
|
|
62
|
+
return newName;
|
|
63
|
+
};
|
|
64
|
+
var headingName = existingHeadingName || generateUniqueName('Heading');
|
|
65
|
+
context.report({
|
|
66
|
+
node: node.openingElement,
|
|
67
|
+
messageId: 'noHtmlHeading',
|
|
68
|
+
data: {
|
|
69
|
+
name: nodeName
|
|
70
|
+
},
|
|
71
|
+
suggest: [{
|
|
72
|
+
desc: 'Replace with Heading component from @atlaskit/heading',
|
|
73
|
+
fix: function fix(fixer) {
|
|
74
|
+
var _node$closingElement;
|
|
75
|
+
var openingTagRange = node.openingElement.range;
|
|
76
|
+
var closingTagRange = (_node$closingElement = node.closingElement) === null || _node$closingElement === void 0 ? void 0 : _node$closingElement.range;
|
|
77
|
+
var elementName = isNodeOfType(node.openingElement.name, 'JSXIdentifier') ? node.openingElement.name.name : '';
|
|
78
|
+
var attributesText = node.openingElement.attributes
|
|
79
|
+
// Don't bring in the "role" or the "aria-level" because it's not needed
|
|
80
|
+
.filter(function (attr) {
|
|
81
|
+
return !isNodeOfType(attr, 'JSXAttribute') || typeof attr.name.name === 'string' && !['role', 'aria-level'].includes(attr.name.name);
|
|
82
|
+
}).map(function (attr) {
|
|
83
|
+
return sourceCode.getText(attr);
|
|
84
|
+
}).join(' ');
|
|
85
|
+
|
|
86
|
+
// Get the heading level
|
|
87
|
+
var headingLevel = '';
|
|
88
|
+
var ariaLevel = node.openingElement.attributes.find(function (attr) {
|
|
89
|
+
return isNodeOfType(attr, 'JSXAttribute') && attr.name.name === 'aria-level';
|
|
90
|
+
});
|
|
91
|
+
if (ariaLevel && isNodeOfType(ariaLevel, 'JSXAttribute')) {
|
|
92
|
+
var _ariaLevel$value, _ariaLevel$value2;
|
|
93
|
+
// If it's a string
|
|
94
|
+
if (((_ariaLevel$value = ariaLevel.value) === null || _ariaLevel$value === void 0 ? void 0 : _ariaLevel$value.type) === 'Literal' && ariaLevel.value.value) {
|
|
95
|
+
headingLevel = "h".concat(ariaLevel.value.value);
|
|
96
|
+
// If it's a number or some other literal in an expression container
|
|
97
|
+
} else if (((_ariaLevel$value2 = ariaLevel.value) === null || _ariaLevel$value2 === void 0 ? void 0 : _ariaLevel$value2.type) === 'JSXExpressionContainer' && ariaLevel.value.expression.type === 'Literal' && ariaLevel.value.expression.value) {
|
|
98
|
+
headingLevel = "h".concat(ariaLevel.value.expression.value);
|
|
99
|
+
}
|
|
100
|
+
} else if (elementName.match(/h[1-6]/)) {
|
|
101
|
+
headingLevel = elementName;
|
|
102
|
+
}
|
|
103
|
+
var fixers = [];
|
|
104
|
+
|
|
105
|
+
// Replace <a> with <Heading> and retain attributes
|
|
106
|
+
if (openingTagRange) {
|
|
107
|
+
if (node.openingElement.selfClosing) {
|
|
108
|
+
fixers.push(fixer.replaceTextRange([openingTagRange[0] + 1, openingTagRange[1] - 1], "".concat(headingName).concat(headingLevel ? " as=\"".concat(headingLevel, "\"") : '').concat(attributesText ? " ".concat(attributesText) : '', " /")));
|
|
109
|
+
} else {
|
|
110
|
+
fixers.push(fixer.replaceTextRange([openingTagRange[0] + 1, openingTagRange[1] - 1], "".concat(headingName).concat(headingLevel ? " as=\"".concat(headingLevel, "\"") : '').concat(attributesText ? " ".concat(attributesText) : '')));
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
if (closingTagRange && !node.openingElement.selfClosing) {
|
|
114
|
+
fixers.push(fixer.replaceTextRange([closingTagRange[0] + 2, closingTagRange[1] - 1], headingName));
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Add import if not present
|
|
118
|
+
if (!existingHeadingName) {
|
|
119
|
+
var importStatement = "import ".concat(headingName, " from '@atlaskit/heading';\n");
|
|
120
|
+
fixers.push(fixer.insertTextBefore(sourceCode.ast, importStatement));
|
|
121
|
+
}
|
|
122
|
+
return fixers;
|
|
123
|
+
}
|
|
124
|
+
}]
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/* eslint-disable @repo/internal/react/require-jsdoc */
|
|
2
|
+
|
|
3
|
+
import { isNodeOfType } from 'eslint-codemod-utils';
|
|
4
|
+
import { getScope } from '@atlaskit/eslint-utils/context-compat';
|
|
5
|
+
import { getJsxElementByName } from '../../../utils/get-jsx-element-by-name';
|
|
6
|
+
import { getStyledComponentCall } from '../../../utils/get-styled-component-call';
|
|
7
|
+
import { isSupportedForLint } from '../supported';
|
|
8
|
+
export var StyledComponent = {
|
|
9
|
+
lint: function lint(node, _ref) {
|
|
10
|
+
var _getJsxElementByName;
|
|
11
|
+
var context = _ref.context;
|
|
12
|
+
if (!isNodeOfType(node, 'CallExpression') || !isNodeOfType(node.callee, 'MemberExpression') || !isNodeOfType(node.callee.object, 'Identifier') || !isNodeOfType(node.callee.property, 'Identifier')) {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
var styles = getStyledComponentCall(node);
|
|
16
|
+
var elementName = node.callee.property.name;
|
|
17
|
+
if (!styles || !isNodeOfType(styles.id, 'Identifier')) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
var jsxElement = (_getJsxElementByName = getJsxElementByName(styles.id.name, getScope(context, node))) === null || _getJsxElementByName === void 0 ? void 0 : _getJsxElementByName.parent;
|
|
21
|
+
if (!jsxElement) {
|
|
22
|
+
// If there's no JSX element, we can't determine if it's being used as an heading or not
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
if (jsxElement && !isSupportedForLint(jsxElement, elementName)) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
context.report({
|
|
29
|
+
node: styles,
|
|
30
|
+
messageId: 'noHtmlHeading',
|
|
31
|
+
data: {
|
|
32
|
+
name: node.callee.property.name
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { isNodeOfType } from 'eslint-codemod-utils';
|
|
2
|
+
import * as ast from '../../../ast-nodes';
|
|
3
|
+
var supportedElements = [{
|
|
4
|
+
name: 'h1'
|
|
5
|
+
}, {
|
|
6
|
+
name: 'h2'
|
|
7
|
+
}, {
|
|
8
|
+
name: 'h3'
|
|
9
|
+
}, {
|
|
10
|
+
name: 'h4'
|
|
11
|
+
}, {
|
|
12
|
+
name: 'h5'
|
|
13
|
+
}, {
|
|
14
|
+
name: 'h6'
|
|
15
|
+
}, {
|
|
16
|
+
name: '*',
|
|
17
|
+
attributes: [{
|
|
18
|
+
name: 'role',
|
|
19
|
+
values: ['heading']
|
|
20
|
+
}]
|
|
21
|
+
}];
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Determines if the given JSX element is a supported element to lint with this rule.
|
|
25
|
+
*/
|
|
26
|
+
export function isSupportedForLint(jsxNode, elementName) {
|
|
27
|
+
if (!isNodeOfType(jsxNode, 'JSXElement')) {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Allow passing in the element name because the jsxNode doesn't
|
|
32
|
+
// represent the element name with styled components
|
|
33
|
+
var elName = elementName || ast.JSXElement.getName(jsxNode);
|
|
34
|
+
if (!elName) {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Only check native HTML elements, not components
|
|
39
|
+
if (elName[0] !== elName[0].toLowerCase()) {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
var supportedElement = supportedElements.find(function (_ref) {
|
|
43
|
+
var name = _ref.name;
|
|
44
|
+
return name === elName;
|
|
45
|
+
});
|
|
46
|
+
if (!supportedElement) {
|
|
47
|
+
supportedElement = supportedElements.find(function (_ref2) {
|
|
48
|
+
var name = _ref2.name;
|
|
49
|
+
return name === '*';
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
if (!supportedElement) {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Check if the element has any attributes that are not supported
|
|
57
|
+
var attributes = ast.JSXElement.getAttributes(jsxNode);
|
|
58
|
+
if (supportedElement.attributes && !supportedElement.attributes.every(function (_ref3) {
|
|
59
|
+
var name = _ref3.name,
|
|
60
|
+
values = _ref3.values;
|
|
61
|
+
return attributes.some(function (attribute) {
|
|
62
|
+
if (attribute.type === 'JSXSpreadAttribute') {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
var isMatchingName = attribute.name.name === name;
|
|
66
|
+
var isMatchingValues = values && attribute.value && attribute.value.type === 'Literal' && typeof attribute.value.value === 'string' && (values === null || values === void 0 ? void 0 : values.includes(attribute.value.value));
|
|
67
|
+
return isMatchingName && isMatchingValues;
|
|
68
|
+
});
|
|
69
|
+
})) {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { createLintRule } from '../utils/create-rule';
|
|
2
|
+
import { JSXElement as _JSXElement, StyledComponent } from './node-types';
|
|
3
|
+
var rule = createLintRule({
|
|
4
|
+
meta: {
|
|
5
|
+
name: 'no-html-select',
|
|
6
|
+
type: 'suggestion',
|
|
7
|
+
hasSuggestions: true,
|
|
8
|
+
docs: {
|
|
9
|
+
description: 'Discourage direct usage of HTML select elements in favor of the Atlassian Design System select component.',
|
|
10
|
+
recommended: true,
|
|
11
|
+
severity: 'warn'
|
|
12
|
+
},
|
|
13
|
+
messages: {
|
|
14
|
+
noHtmlSelect: "This <{{ name }}> should be replaced with the select component from the Atlassian Design System. ADS select components have event tracking, ensure accessible implementations, and provide access to ADS styling features like design tokens."
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
create: function create(context) {
|
|
18
|
+
return {
|
|
19
|
+
// transforms styled.<anchor>(...) usages
|
|
20
|
+
CallExpression: function CallExpression(node) {
|
|
21
|
+
StyledComponent.lint(node, {
|
|
22
|
+
context: context
|
|
23
|
+
});
|
|
24
|
+
},
|
|
25
|
+
// transforms <anchor css={...}> usages
|
|
26
|
+
JSXElement: function JSXElement(node) {
|
|
27
|
+
_JSXElement.lint(node, {
|
|
28
|
+
context: context
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
export default rule;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as ast from '../../../../ast-nodes';
|
|
2
|
+
import { isSupportedForLint } from '../supported';
|
|
3
|
+
export var JSXElement = {
|
|
4
|
+
lint: function lint(node, _ref) {
|
|
5
|
+
var context = _ref.context;
|
|
6
|
+
if (!isSupportedForLint(node)) {
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
var nodeName = ast.JSXElement.getName(node);
|
|
10
|
+
context.report({
|
|
11
|
+
node: node.openingElement,
|
|
12
|
+
messageId: 'noHtmlSelect',
|
|
13
|
+
data: {
|
|
14
|
+
name: nodeName
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/* eslint-disable @repo/internal/react/require-jsdoc */
|
|
2
|
+
|
|
3
|
+
import { isNodeOfType } from 'eslint-codemod-utils';
|
|
4
|
+
import { getScope } from '@atlaskit/eslint-utils/context-compat';
|
|
5
|
+
import { getJsxElementByName } from '../../../utils/get-jsx-element-by-name';
|
|
6
|
+
import { getStyledComponentCall } from '../../../utils/get-styled-component-call';
|
|
7
|
+
import { isSupportedForLint } from '../supported';
|
|
8
|
+
export var StyledComponent = {
|
|
9
|
+
lint: function lint(node, _ref) {
|
|
10
|
+
var _getJsxElementByName;
|
|
11
|
+
var context = _ref.context;
|
|
12
|
+
if (!isNodeOfType(node, 'CallExpression') || !isNodeOfType(node.callee, 'MemberExpression') || !isNodeOfType(node.callee.object, 'Identifier') || !isNodeOfType(node.callee.property, 'Identifier')) {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
var styles = getStyledComponentCall(node);
|
|
16
|
+
var elementName = node.callee.property.name;
|
|
17
|
+
if (!styles || !isNodeOfType(styles.id, 'Identifier')) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
var jsxElement = (_getJsxElementByName = getJsxElementByName(styles.id.name, getScope(context, node))) === null || _getJsxElementByName === void 0 ? void 0 : _getJsxElementByName.parent;
|
|
21
|
+
if (!jsxElement) {
|
|
22
|
+
// If there's no JSX element, we can't determine if it's being used as an select or not
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
if (jsxElement && !isSupportedForLint(jsxElement, elementName)) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
context.report({
|
|
29
|
+
node: styles,
|
|
30
|
+
messageId: 'noHtmlSelect',
|
|
31
|
+
data: {
|
|
32
|
+
name: node.callee.property.name
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { isNodeOfType } from 'eslint-codemod-utils';
|
|
2
|
+
import * as ast from '../../../ast-nodes';
|
|
3
|
+
var supportedElements = [{
|
|
4
|
+
name: 'select'
|
|
5
|
+
}];
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Determines if the given JSX element is a supported element to lint with this rule.
|
|
9
|
+
*/
|
|
10
|
+
export function isSupportedForLint(jsxNode, elementName) {
|
|
11
|
+
if (!isNodeOfType(jsxNode, 'JSXElement')) {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Allow passing in the element name because the jsxNode doesn't
|
|
16
|
+
// represent the element name with styled components
|
|
17
|
+
var elName = elementName || ast.JSXElement.getName(jsxNode);
|
|
18
|
+
if (!elName) {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Only check native HTML elements, not components
|
|
23
|
+
if (elName[0] !== elName[0].toLowerCase()) {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
var supportedElement = supportedElements.find(function (_ref) {
|
|
27
|
+
var name = _ref.name;
|
|
28
|
+
return name === elName;
|
|
29
|
+
});
|
|
30
|
+
if (!supportedElement) {
|
|
31
|
+
supportedElement = supportedElements.find(function (_ref2) {
|
|
32
|
+
var name = _ref2.name;
|
|
33
|
+
return name === '*';
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
if (!supportedElement) {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Check if the element has any attributes that are not supported
|
|
41
|
+
var attributes = ast.JSXElement.getAttributes(jsxNode);
|
|
42
|
+
if (supportedElement.attributes && !supportedElement.attributes.every(function (_ref3) {
|
|
43
|
+
var name = _ref3.name,
|
|
44
|
+
values = _ref3.values;
|
|
45
|
+
return attributes.some(function (attribute) {
|
|
46
|
+
if (attribute.type === 'JSXSpreadAttribute') {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
var isMatchingName = attribute.name.name === name;
|
|
50
|
+
var isMatchingValues = values && attribute.value && attribute.value.type === 'Literal' && typeof attribute.value.value === 'string' && (values === null || values === void 0 ? void 0 : values.includes(attribute.value.value));
|
|
51
|
+
return isMatchingName && isMatchingValues;
|
|
52
|
+
});
|
|
53
|
+
})) {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
@@ -35,8 +35,10 @@ export declare const plugin: {
|
|
|
35
35
|
'no-html-anchor': import("eslint").Rule.RuleModule;
|
|
36
36
|
'no-html-button': import("eslint").Rule.RuleModule;
|
|
37
37
|
'no-html-checkbox': import("eslint").Rule.RuleModule;
|
|
38
|
+
'no-html-heading': import("eslint").Rule.RuleModule;
|
|
38
39
|
'no-html-image': import("eslint").Rule.RuleModule;
|
|
39
40
|
'no-html-range': import("eslint").Rule.RuleModule;
|
|
41
|
+
'no-html-select': import("eslint").Rule.RuleModule;
|
|
40
42
|
'no-invalid-css-map': import("eslint").Rule.RuleModule;
|
|
41
43
|
'no-keyframes-tagged-template-expression': import("eslint").Rule.RuleModule;
|
|
42
44
|
'no-legacy-icons': import("eslint").Rule.RuleModule;
|
|
@@ -91,8 +93,10 @@ export declare const plugin: {
|
|
|
91
93
|
'@atlaskit/design-system/no-html-anchor': "warn";
|
|
92
94
|
'@atlaskit/design-system/no-html-button': "warn";
|
|
93
95
|
'@atlaskit/design-system/no-html-checkbox': "warn";
|
|
96
|
+
'@atlaskit/design-system/no-html-heading': "warn";
|
|
94
97
|
'@atlaskit/design-system/no-html-image': "warn";
|
|
95
98
|
'@atlaskit/design-system/no-html-range': "warn";
|
|
99
|
+
'@atlaskit/design-system/no-html-select': "warn";
|
|
96
100
|
'@atlaskit/design-system/no-invalid-css-map': ["error", {
|
|
97
101
|
allowedFunctionCalls: string[][];
|
|
98
102
|
}];
|
|
@@ -151,8 +155,10 @@ export declare const plugin: {
|
|
|
151
155
|
'@atlaskit/design-system/no-html-anchor': "warn";
|
|
152
156
|
'@atlaskit/design-system/no-html-button': "warn";
|
|
153
157
|
'@atlaskit/design-system/no-html-checkbox': "warn";
|
|
158
|
+
'@atlaskit/design-system/no-html-heading': "warn";
|
|
154
159
|
'@atlaskit/design-system/no-html-image': "warn";
|
|
155
160
|
'@atlaskit/design-system/no-html-range': "warn";
|
|
161
|
+
'@atlaskit/design-system/no-html-select': "warn";
|
|
156
162
|
'@atlaskit/design-system/no-invalid-css-map': ["error", {
|
|
157
163
|
allowedFunctionCalls: string[][];
|
|
158
164
|
}];
|
|
@@ -204,8 +210,10 @@ export declare const plugin: {
|
|
|
204
210
|
'@atlaskit/design-system/no-html-anchor': "warn";
|
|
205
211
|
'@atlaskit/design-system/no-html-button': "warn";
|
|
206
212
|
'@atlaskit/design-system/no-html-checkbox': "warn";
|
|
213
|
+
'@atlaskit/design-system/no-html-heading': "warn";
|
|
207
214
|
'@atlaskit/design-system/no-html-image': "warn";
|
|
208
215
|
'@atlaskit/design-system/no-html-range': "warn";
|
|
216
|
+
'@atlaskit/design-system/no-html-select': "warn";
|
|
209
217
|
'@atlaskit/design-system/no-invalid-css-map': ["error", {
|
|
210
218
|
allowedFunctionCalls: string[][];
|
|
211
219
|
}];
|
|
@@ -248,8 +256,10 @@ export declare const plugin: {
|
|
|
248
256
|
'@atlaskit/design-system/no-html-anchor': "warn";
|
|
249
257
|
'@atlaskit/design-system/no-html-button': "warn";
|
|
250
258
|
'@atlaskit/design-system/no-html-checkbox': "warn";
|
|
259
|
+
'@atlaskit/design-system/no-html-heading': "warn";
|
|
251
260
|
'@atlaskit/design-system/no-html-image': "warn";
|
|
252
261
|
'@atlaskit/design-system/no-html-range': "warn";
|
|
262
|
+
'@atlaskit/design-system/no-html-select': "warn";
|
|
253
263
|
'@atlaskit/design-system/no-invalid-css-map': ["error", {
|
|
254
264
|
allowedFunctionCalls: string[][];
|
|
255
265
|
}];
|
|
@@ -298,8 +308,10 @@ declare const configs: {
|
|
|
298
308
|
'@atlaskit/design-system/no-html-anchor': "warn";
|
|
299
309
|
'@atlaskit/design-system/no-html-button': "warn";
|
|
300
310
|
'@atlaskit/design-system/no-html-checkbox': "warn";
|
|
311
|
+
'@atlaskit/design-system/no-html-heading': "warn";
|
|
301
312
|
'@atlaskit/design-system/no-html-image': "warn";
|
|
302
313
|
'@atlaskit/design-system/no-html-range': "warn";
|
|
314
|
+
'@atlaskit/design-system/no-html-select': "warn";
|
|
303
315
|
'@atlaskit/design-system/no-invalid-css-map': ["error", {
|
|
304
316
|
allowedFunctionCalls: string[][];
|
|
305
317
|
}];
|
|
@@ -358,8 +370,10 @@ declare const configs: {
|
|
|
358
370
|
'@atlaskit/design-system/no-html-anchor': "warn";
|
|
359
371
|
'@atlaskit/design-system/no-html-button': "warn";
|
|
360
372
|
'@atlaskit/design-system/no-html-checkbox': "warn";
|
|
373
|
+
'@atlaskit/design-system/no-html-heading': "warn";
|
|
361
374
|
'@atlaskit/design-system/no-html-image': "warn";
|
|
362
375
|
'@atlaskit/design-system/no-html-range': "warn";
|
|
376
|
+
'@atlaskit/design-system/no-html-select': "warn";
|
|
363
377
|
'@atlaskit/design-system/no-invalid-css-map': ["error", {
|
|
364
378
|
allowedFunctionCalls: string[][];
|
|
365
379
|
}];
|
|
@@ -411,8 +425,10 @@ declare const configs: {
|
|
|
411
425
|
'@atlaskit/design-system/no-html-anchor': "warn";
|
|
412
426
|
'@atlaskit/design-system/no-html-button': "warn";
|
|
413
427
|
'@atlaskit/design-system/no-html-checkbox': "warn";
|
|
428
|
+
'@atlaskit/design-system/no-html-heading': "warn";
|
|
414
429
|
'@atlaskit/design-system/no-html-image': "warn";
|
|
415
430
|
'@atlaskit/design-system/no-html-range': "warn";
|
|
431
|
+
'@atlaskit/design-system/no-html-select': "warn";
|
|
416
432
|
'@atlaskit/design-system/no-invalid-css-map': ["error", {
|
|
417
433
|
allowedFunctionCalls: string[][];
|
|
418
434
|
}];
|
|
@@ -455,8 +471,10 @@ declare const configs: {
|
|
|
455
471
|
'@atlaskit/design-system/no-html-anchor': "warn";
|
|
456
472
|
'@atlaskit/design-system/no-html-button': "warn";
|
|
457
473
|
'@atlaskit/design-system/no-html-checkbox': "warn";
|
|
474
|
+
'@atlaskit/design-system/no-html-heading': "warn";
|
|
458
475
|
'@atlaskit/design-system/no-html-image': "warn";
|
|
459
476
|
'@atlaskit/design-system/no-html-range': "warn";
|
|
477
|
+
'@atlaskit/design-system/no-html-select': "warn";
|
|
460
478
|
'@atlaskit/design-system/no-invalid-css-map': ["error", {
|
|
461
479
|
allowedFunctionCalls: string[][];
|
|
462
480
|
}];
|
|
@@ -18,8 +18,10 @@ declare const _default: {
|
|
|
18
18
|
'@atlaskit/design-system/no-html-anchor': "warn";
|
|
19
19
|
'@atlaskit/design-system/no-html-button': "warn";
|
|
20
20
|
'@atlaskit/design-system/no-html-checkbox': "warn";
|
|
21
|
+
'@atlaskit/design-system/no-html-heading': "warn";
|
|
21
22
|
'@atlaskit/design-system/no-html-image': "warn";
|
|
22
23
|
'@atlaskit/design-system/no-html-range': "warn";
|
|
24
|
+
'@atlaskit/design-system/no-html-select': "warn";
|
|
23
25
|
'@atlaskit/design-system/no-invalid-css-map': ["error", {
|
|
24
26
|
allowedFunctionCalls: string[][];
|
|
25
27
|
}];
|
|
@@ -18,8 +18,10 @@ declare const _default: {
|
|
|
18
18
|
'@atlaskit/design-system/no-html-anchor': "warn";
|
|
19
19
|
'@atlaskit/design-system/no-html-button': "warn";
|
|
20
20
|
'@atlaskit/design-system/no-html-checkbox': "warn";
|
|
21
|
+
'@atlaskit/design-system/no-html-heading': "warn";
|
|
21
22
|
'@atlaskit/design-system/no-html-image': "warn";
|
|
22
23
|
'@atlaskit/design-system/no-html-range': "warn";
|
|
24
|
+
'@atlaskit/design-system/no-html-select': "warn";
|
|
23
25
|
'@atlaskit/design-system/no-invalid-css-map': ["error", {
|
|
24
26
|
allowedFunctionCalls: string[][];
|
|
25
27
|
}];
|
|
@@ -13,8 +13,10 @@ declare const _default: {
|
|
|
13
13
|
'@atlaskit/design-system/no-html-anchor': "warn";
|
|
14
14
|
'@atlaskit/design-system/no-html-button': "warn";
|
|
15
15
|
'@atlaskit/design-system/no-html-checkbox': "warn";
|
|
16
|
+
'@atlaskit/design-system/no-html-heading': "warn";
|
|
16
17
|
'@atlaskit/design-system/no-html-image': "warn";
|
|
17
18
|
'@atlaskit/design-system/no-html-range': "warn";
|
|
19
|
+
'@atlaskit/design-system/no-html-select': "warn";
|
|
18
20
|
'@atlaskit/design-system/no-invalid-css-map': ["error", {
|
|
19
21
|
allowedFunctionCalls: string[][];
|
|
20
22
|
}];
|
|
@@ -13,8 +13,10 @@ declare const _default: {
|
|
|
13
13
|
'@atlaskit/design-system/no-html-anchor': "warn";
|
|
14
14
|
'@atlaskit/design-system/no-html-button': "warn";
|
|
15
15
|
'@atlaskit/design-system/no-html-checkbox': "warn";
|
|
16
|
+
'@atlaskit/design-system/no-html-heading': "warn";
|
|
16
17
|
'@atlaskit/design-system/no-html-image': "warn";
|
|
17
18
|
'@atlaskit/design-system/no-html-range': "warn";
|
|
19
|
+
'@atlaskit/design-system/no-html-select': "warn";
|
|
18
20
|
'@atlaskit/design-system/no-invalid-css-map': ["error", {
|
|
19
21
|
allowedFunctionCalls: string[][];
|
|
20
22
|
}];
|
|
@@ -19,8 +19,10 @@ export declare const rules: {
|
|
|
19
19
|
'no-html-anchor': import("eslint").Rule.RuleModule;
|
|
20
20
|
'no-html-button': import("eslint").Rule.RuleModule;
|
|
21
21
|
'no-html-checkbox': import("eslint").Rule.RuleModule;
|
|
22
|
+
'no-html-heading': import("eslint").Rule.RuleModule;
|
|
22
23
|
'no-html-image': import("eslint").Rule.RuleModule;
|
|
23
24
|
'no-html-range': import("eslint").Rule.RuleModule;
|
|
25
|
+
'no-html-select': import("eslint").Rule.RuleModule;
|
|
24
26
|
'no-invalid-css-map': import("eslint").Rule.RuleModule;
|
|
25
27
|
'no-keyframes-tagged-template-expression': import("eslint").Rule.RuleModule;
|
|
26
28
|
'no-legacy-icons': import("eslint").Rule.RuleModule;
|