@atlaskit/eslint-plugin-design-system 9.6.0 → 10.0.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 +1004 -411
- package/README.md +7 -5
- package/constellation/consistent-css-prop-usage/usage.mdx +44 -30
- package/constellation/ensure-design-token-usage/usage.mdx +12 -7
- package/constellation/ensure-design-token-usage-preview/usage.mdx +2 -1
- package/constellation/icon-label/usage.mdx +5 -3
- package/constellation/index/usage.mdx +5 -2
- package/constellation/no-banned-imports/usage.mdx +3 -1
- package/constellation/no-css-tagged-template-expression/usage.mdx +22 -17
- package/constellation/no-deprecated-apis/usage.mdx +33 -27
- package/constellation/no-deprecated-design-token-usage/usage.mdx +7 -4
- package/constellation/no-deprecated-imports/usage.mdx +31 -27
- package/constellation/no-direct-use-of-web-platform-drag-and-drop/usage.mdx +19 -10
- package/constellation/no-empty-styled-expression/usage.mdx +19 -14
- package/constellation/no-exported-css/usage.mdx +15 -10
- package/constellation/no-exported-keyframes/usage.mdx +15 -10
- package/constellation/no-html-anchor/usage.mdx +40 -0
- package/constellation/no-html-button/usage.mdx +52 -0
- package/constellation/no-invalid-css-map/usage.mdx +69 -58
- package/constellation/no-keyframes-tagged-template-expression/usage.mdx +24 -18
- package/constellation/no-margin/usage.mdx +3 -2
- package/constellation/no-nested-styles/usage.mdx +16 -16
- package/constellation/no-physical-properties/usage.mdx +13 -13
- package/constellation/no-styled-tagged-template-expression/usage.mdx +39 -34
- package/constellation/no-unsafe-design-token-usage/usage.mdx +8 -7
- package/constellation/no-unsafe-style-overrides/usage.mdx +10 -7
- package/constellation/no-unsupported-drag-and-drop-libraries/usage.mdx +8 -2
- package/constellation/prefer-primitives/usage.mdx +3 -2
- package/constellation/use-button-group-label/usage.mdx +4 -2
- package/constellation/use-drawer-label/usage.mdx +4 -2
- package/constellation/use-heading/usage.mdx +7 -4
- package/constellation/use-heading-level-in-spotlight-card/usage.mdx +3 -2
- package/constellation/use-href-in-link-item/usage.mdx +2 -1
- package/constellation/use-popup-label/usage.mdx +56 -0
- package/constellation/use-primitives/usage.mdx +40 -39
- package/constellation/use-primitives-text/usage.mdx +7 -3
- package/constellation/use-tokens-space/usage.mdx +7 -3
- package/constellation/use-tokens-typography/usage.mdx +15 -6
- package/constellation/use-visually-hidden/usage.mdx +2 -1
- package/dist/cjs/common/token-maps.partial.js +49 -0
- package/dist/cjs/index.codegen.js +1 -1
- package/dist/cjs/presets/all.codegen.js +4 -2
- package/dist/cjs/presets/recommended.codegen.js +2 -1
- package/dist/cjs/rules/index.codegen.js +7 -3
- package/dist/cjs/rules/no-html-anchor/index.js +39 -0
- package/dist/cjs/rules/no-html-anchor/node-types/index.js +19 -0
- package/dist/cjs/rules/no-html-anchor/node-types/jsx-element/index.js +28 -0
- package/dist/cjs/rules/no-html-anchor/node-types/styled-component/get-styled-component-call.js +47 -0
- package/dist/cjs/rules/no-html-anchor/node-types/styled-component/index.js +37 -0
- package/dist/cjs/rules/no-html-anchor/node-types/supported.js +66 -0
- package/dist/cjs/rules/no-html-anchor/utils/get-jsx-element-by-name.js +53 -0
- package/dist/cjs/rules/no-html-button/index.js +39 -0
- package/dist/cjs/rules/no-html-button/node-types/index.js +19 -0
- package/dist/cjs/rules/no-html-button/node-types/jsx-element/index.js +28 -0
- package/dist/cjs/rules/no-html-button/node-types/styled-component/get-styled-component-call.js +47 -0
- package/dist/cjs/rules/no-html-button/node-types/styled-component/index.js +37 -0
- package/dist/cjs/rules/no-html-button/node-types/supported.js +79 -0
- package/dist/cjs/rules/no-html-button/utils/get-jsx-element-by-name.js +53 -0
- package/dist/cjs/rules/use-popup-label/index.js +90 -0
- package/dist/es2019/common/token-maps.partial.js +42 -0
- package/dist/es2019/index.codegen.js +1 -1
- package/dist/es2019/presets/all.codegen.js +4 -2
- package/dist/es2019/presets/recommended.codegen.js +2 -1
- package/dist/es2019/rules/index.codegen.js +7 -3
- package/dist/es2019/rules/no-html-anchor/index.js +33 -0
- package/dist/es2019/rules/no-html-anchor/node-types/index.js +2 -0
- package/dist/es2019/rules/no-html-anchor/node-types/jsx-element/index.js +20 -0
- package/dist/es2019/rules/no-html-anchor/node-types/styled-component/get-styled-component-call.js +42 -0
- package/dist/es2019/rules/no-html-anchor/node-types/styled-component/index.js +32 -0
- package/dist/es2019/rules/no-html-anchor/node-types/supported.js +56 -0
- package/dist/es2019/rules/no-html-anchor/utils/get-jsx-element-by-name.js +39 -0
- package/dist/es2019/rules/no-html-button/index.js +33 -0
- package/dist/es2019/rules/no-html-button/node-types/index.js +2 -0
- package/dist/es2019/rules/no-html-button/node-types/jsx-element/index.js +20 -0
- package/dist/es2019/rules/no-html-button/node-types/styled-component/get-styled-component-call.js +42 -0
- package/dist/es2019/rules/no-html-button/node-types/styled-component/index.js +32 -0
- package/dist/es2019/rules/no-html-button/node-types/supported.js +69 -0
- package/dist/es2019/rules/no-html-button/utils/get-jsx-element-by-name.js +39 -0
- package/dist/es2019/rules/use-popup-label/index.js +80 -0
- package/dist/esm/common/token-maps.partial.js +42 -0
- package/dist/esm/index.codegen.js +1 -1
- package/dist/esm/presets/all.codegen.js +4 -2
- package/dist/esm/presets/recommended.codegen.js +2 -1
- package/dist/esm/rules/index.codegen.js +7 -3
- package/dist/esm/rules/no-html-anchor/index.js +33 -0
- package/dist/esm/rules/no-html-anchor/node-types/index.js +2 -0
- package/dist/esm/rules/no-html-anchor/node-types/jsx-element/index.js +19 -0
- package/dist/esm/rules/no-html-anchor/node-types/styled-component/get-styled-component-call.js +42 -0
- package/dist/esm/rules/no-html-anchor/node-types/styled-component/index.js +31 -0
- package/dist/esm/rules/no-html-anchor/node-types/supported.js +57 -0
- package/dist/esm/rules/no-html-anchor/utils/get-jsx-element-by-name.js +47 -0
- package/dist/esm/rules/no-html-button/index.js +33 -0
- package/dist/esm/rules/no-html-button/node-types/index.js +2 -0
- package/dist/esm/rules/no-html-button/node-types/jsx-element/index.js +19 -0
- package/dist/esm/rules/no-html-button/node-types/styled-component/get-styled-component-call.js +42 -0
- package/dist/esm/rules/no-html-button/node-types/styled-component/index.js +31 -0
- package/dist/esm/rules/no-html-button/node-types/supported.js +70 -0
- package/dist/esm/rules/no-html-button/utils/get-jsx-element-by-name.js +47 -0
- package/dist/esm/rules/use-popup-label/index.js +84 -0
- package/dist/types/common/token-maps.partial.d.ts +65 -0
- package/dist/types/index.codegen.d.ts +4 -1
- package/dist/types/presets/all.codegen.d.ts +4 -2
- package/dist/types/presets/recommended.codegen.d.ts +2 -1
- package/dist/types/rules/index.codegen.d.ts +3 -1
- package/dist/types/rules/no-html-anchor/index.d.ts +3 -0
- package/dist/types/rules/no-html-anchor/node-types/index.d.ts +2 -0
- package/dist/types/rules/no-html-anchor/node-types/jsx-element/index.d.ts +8 -0
- package/dist/types/rules/no-html-anchor/node-types/styled-component/get-styled-component-call.d.ts +6 -0
- package/dist/types/rules/no-html-anchor/node-types/styled-component/index.d.ts +8 -0
- package/dist/types/rules/no-html-anchor/node-types/supported.d.ts +7 -0
- package/dist/types/rules/no-html-anchor/utils/get-jsx-element-by-name.d.ts +6 -0
- package/dist/types/rules/no-html-button/index.d.ts +3 -0
- package/dist/types/rules/no-html-button/node-types/index.d.ts +2 -0
- package/dist/types/rules/no-html-button/node-types/jsx-element/index.d.ts +8 -0
- package/dist/types/rules/no-html-button/node-types/styled-component/get-styled-component-call.d.ts +6 -0
- package/dist/types/rules/no-html-button/node-types/styled-component/index.d.ts +8 -0
- package/dist/types/rules/no-html-button/node-types/supported.d.ts +7 -0
- package/dist/types/rules/no-html-button/utils/get-jsx-element-by-name.d.ts +6 -0
- package/dist/types/rules/use-popup-label/index.d.ts +3 -0
- package/dist/types/rules/use-tokens-typography/utils.d.ts +0 -33
- package/dist/types-ts4.5/common/token-maps.partial.d.ts +65 -0
- package/dist/types-ts4.5/index.codegen.d.ts +4 -1
- package/dist/types-ts4.5/presets/all.codegen.d.ts +4 -2
- package/dist/types-ts4.5/presets/recommended.codegen.d.ts +2 -1
- package/dist/types-ts4.5/rules/index.codegen.d.ts +3 -1
- package/dist/types-ts4.5/rules/no-html-anchor/node-types/index.d.ts +2 -0
- package/dist/types-ts4.5/rules/no-html-anchor/node-types/jsx-element/index.d.ts +8 -0
- package/dist/types-ts4.5/rules/no-html-anchor/node-types/styled-component/get-styled-component-call.d.ts +6 -0
- package/dist/types-ts4.5/rules/no-html-anchor/node-types/styled-component/index.d.ts +8 -0
- package/dist/types-ts4.5/rules/no-html-anchor/node-types/supported.d.ts +7 -0
- package/dist/types-ts4.5/rules/no-html-anchor/utils/get-jsx-element-by-name.d.ts +6 -0
- package/dist/types-ts4.5/rules/no-html-button/node-types/index.d.ts +2 -0
- package/dist/types-ts4.5/rules/no-html-button/node-types/jsx-element/index.d.ts +8 -0
- package/dist/types-ts4.5/rules/no-html-button/node-types/styled-component/get-styled-component-call.d.ts +6 -0
- package/dist/types-ts4.5/rules/no-html-button/node-types/styled-component/index.d.ts +8 -0
- package/dist/types-ts4.5/rules/no-html-button/node-types/supported.d.ts +7 -0
- package/dist/types-ts4.5/rules/no-html-button/utils/get-jsx-element-by-name.d.ts +6 -0
- package/dist/types-ts4.5/rules/use-popup-label/index.d.ts +3 -0
- package/dist/types-ts4.5/rules/use-tokens-typography/utils.d.ts +0 -33
- package/package.json +4 -3
- package/constellation/no-html-button-element/usage.mdx +0 -26
- package/dist/cjs/rules/no-html-button-element/index.js +0 -107
- package/dist/cjs/rules/no-html-button-element/utils.js +0 -18
- package/dist/es2019/rules/no-html-button-element/index.js +0 -101
- package/dist/es2019/rules/no-html-button-element/utils.js +0 -12
- package/dist/esm/rules/no-html-button-element/index.js +0 -101
- package/dist/esm/rules/no-html-button-element/utils.js +0 -12
- package/dist/types/rules/no-html-button-element/utils.d.ts +0 -2
- package/dist/types-ts4.5/rules/no-html-button-element/utils.d.ts +0 -2
- /package/dist/types-ts4.5/rules/{no-html-button-element → no-html-anchor}/index.d.ts +0 -0
- /package/dist/{types/rules/no-html-button-element → types-ts4.5/rules/no-html-button}/index.d.ts +0 -0
package/dist/es2019/rules/no-html-button/node-types/styled-component/get-styled-component-call.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { closestOfType, isNodeOfType } from 'eslint-codemod-utils';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Returns a styled component
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export const getStyledComponentCall = node => {
|
|
8
|
+
// halts unless we are dealing with a styled component
|
|
9
|
+
if (!isStyledCallExpression(node)) {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
// halts if the component is being exported directly
|
|
13
|
+
if (closestOfType(node, 'ExportNamedDeclaration')) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const styledComponentVariableRef = node.parent;
|
|
17
|
+
// halts if the styled component is not assigned to a variable immediately
|
|
18
|
+
if (!isNodeOfType(styledComponentVariableRef, 'VariableDeclarator')) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
return styledComponentVariableRef;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Some verbose precondition checks but all it does is check
|
|
26
|
+
* a call expression is of form `styled.button` or `styled2.button`
|
|
27
|
+
*/
|
|
28
|
+
const isStyledCallExpression = call => {
|
|
29
|
+
if (!isNodeOfType(call, 'CallExpression')) {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
if (!isNodeOfType(call.callee, 'MemberExpression')) {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
if (!isNodeOfType(call.callee.object, 'Identifier') || !isNodeOfType(call.callee.property, 'Identifier')) {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
if (/^styled2?$/.test(call.callee.object.name)) {
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
return false;
|
|
42
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/* eslint-disable @repo/internal/react/require-jsdoc */
|
|
2
|
+
|
|
3
|
+
import { isNodeOfType } from 'eslint-codemod-utils';
|
|
4
|
+
import { getJsxElementByName } from '../../utils/get-jsx-element-by-name';
|
|
5
|
+
import { isSupportedForLint } from '../supported';
|
|
6
|
+
import { getStyledComponentCall } from './get-styled-component-call';
|
|
7
|
+
export const StyledComponent = {
|
|
8
|
+
lint(node, {
|
|
9
|
+
context
|
|
10
|
+
}) {
|
|
11
|
+
var _getJsxElementByName;
|
|
12
|
+
if (!isNodeOfType(node, 'CallExpression') || !isNodeOfType(node.callee, 'MemberExpression') || !isNodeOfType(node.callee.object, 'Identifier') || !isNodeOfType(node.callee.property, 'Identifier')) {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
const styles = getStyledComponentCall(node);
|
|
16
|
+
const elementName = node.callee.property.name;
|
|
17
|
+
if (!styles || !isNodeOfType(styles.id, 'Identifier')) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
const jsxElement = (_getJsxElementByName = getJsxElementByName(styles.id.name, context.getScope())) === null || _getJsxElementByName === void 0 ? void 0 : _getJsxElementByName.parent;
|
|
21
|
+
if (jsxElement && !isSupportedForLint(jsxElement, elementName)) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
context.report({
|
|
25
|
+
node: styles,
|
|
26
|
+
messageId: 'noHtmlButton',
|
|
27
|
+
data: {
|
|
28
|
+
name: node.callee.property.name
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { isNodeOfType } from 'eslint-codemod-utils';
|
|
2
|
+
import * as ast from '../../../ast-nodes';
|
|
3
|
+
const supportedElements = [{
|
|
4
|
+
name: 'button'
|
|
5
|
+
}, {
|
|
6
|
+
name: 'input',
|
|
7
|
+
attributes: [{
|
|
8
|
+
name: 'type',
|
|
9
|
+
// Values from https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/button_role#best_practices
|
|
10
|
+
values: ['submit', 'reset', 'button', 'image']
|
|
11
|
+
}]
|
|
12
|
+
}, {
|
|
13
|
+
name: '*',
|
|
14
|
+
attributes: [{
|
|
15
|
+
name: 'role',
|
|
16
|
+
values: ['button']
|
|
17
|
+
}]
|
|
18
|
+
}];
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Determines if the given JSX element is a supported element to lint with this rule.
|
|
22
|
+
*/
|
|
23
|
+
export function isSupportedForLint(jsxNode, elementName) {
|
|
24
|
+
if (!isNodeOfType(jsxNode, 'JSXElement')) {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Allow passing in the element name because the jsxNode doesn't
|
|
29
|
+
// represent the element name with styled components
|
|
30
|
+
const elName = elementName || ast.JSXElement.getName(jsxNode);
|
|
31
|
+
if (!elName) {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Only check native HTML elements, not components
|
|
36
|
+
if (elName[0] !== elName[0].toLowerCase()) {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
let supportedElement = supportedElements.find(({
|
|
40
|
+
name
|
|
41
|
+
}) => name === elName);
|
|
42
|
+
if (!supportedElement) {
|
|
43
|
+
supportedElement = supportedElements.find(({
|
|
44
|
+
name
|
|
45
|
+
}) => name === '*');
|
|
46
|
+
}
|
|
47
|
+
if (!supportedElement) {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Check if the element has any attributes that are not supported
|
|
52
|
+
const attributes = ast.JSXElement.getAttributes(jsxNode);
|
|
53
|
+
if (supportedElement.attributes && !supportedElement.attributes.every(({
|
|
54
|
+
name,
|
|
55
|
+
values
|
|
56
|
+
}) => {
|
|
57
|
+
return attributes.some(attribute => {
|
|
58
|
+
if (attribute.type === 'JSXSpreadAttribute') {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
const isMatchingName = attribute.name.name === name;
|
|
62
|
+
const 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));
|
|
63
|
+
return isMatchingName && isMatchingValues;
|
|
64
|
+
});
|
|
65
|
+
})) {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { isNodeOfType } from 'eslint-codemod-utils';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Given a component name finds its JSX usage
|
|
5
|
+
*/
|
|
6
|
+
export const getJsxElementByName = (componentName, scope) => {
|
|
7
|
+
var _variableDeclaration$;
|
|
8
|
+
const variableDeclaration = scope.variables.find(v => v.name === componentName);
|
|
9
|
+
if (!variableDeclaration) {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// length here should be exactly 2 to indicate only two references:
|
|
14
|
+
// one being the variable declaration itself
|
|
15
|
+
// second being the JSX call site
|
|
16
|
+
// we might consider handling multiple local JSX call sites in the future
|
|
17
|
+
// but "this is good enough for now"™️
|
|
18
|
+
if (variableDeclaration.references.length !== 2) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
let jsxUsage = (_variableDeclaration$ = variableDeclaration.references[1]) === null || _variableDeclaration$ === void 0 ? void 0 : _variableDeclaration$.identifier;
|
|
22
|
+
const [firstIdentifier, secondIdentifier] = variableDeclaration.references.map(ref => ref === null || ref === void 0 ? void 0 : ref.identifier);
|
|
23
|
+
// Check if the first reference is a JSXOpeningElement and the second is not or vice versa
|
|
24
|
+
if (isNodeOfType(firstIdentifier, 'JSXIdentifier') && !isNodeOfType(secondIdentifier, 'JSXIdentifier')) {
|
|
25
|
+
jsxUsage = firstIdentifier;
|
|
26
|
+
} else if (isNodeOfType(secondIdentifier, 'JSXIdentifier') && !isNodeOfType(firstIdentifier, 'JSXIdentifier')) {
|
|
27
|
+
jsxUsage = secondIdentifier;
|
|
28
|
+
} else {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
if (!isNodeOfType(jsxUsage, 'JSXIdentifier')) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
const jsxOpeningElement = jsxUsage.parent;
|
|
35
|
+
if (!isNodeOfType(jsxOpeningElement, 'JSXOpeningElement')) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
return jsxOpeningElement;
|
|
39
|
+
};
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
2
|
+
|
|
3
|
+
import { isNodeOfType } from 'eslint-codemod-utils';
|
|
4
|
+
import { createLintRule } from '../utils/create-rule';
|
|
5
|
+
const elementsAccessibleNameProps = ['label', 'titleId'];
|
|
6
|
+
const rule = createLintRule({
|
|
7
|
+
meta: {
|
|
8
|
+
name: 'use-popup-label',
|
|
9
|
+
type: 'suggestion',
|
|
10
|
+
docs: {
|
|
11
|
+
description: 'Encourages to provide accessible name for Atlassian Design System Popup component.',
|
|
12
|
+
recommended: true,
|
|
13
|
+
severity: 'warn'
|
|
14
|
+
},
|
|
15
|
+
messages: {
|
|
16
|
+
missingLabelProp: 'Missing accessible name. If there is no visible content to associate use `label` prop, otherwise pass id of element to `titleId` prop to be associated as label.',
|
|
17
|
+
labelPropShouldHaveContents: 'Define string that labels the interactive element.',
|
|
18
|
+
titleIdShouldHaveValue: '`titleId` should reference the id of element that define accessible name.',
|
|
19
|
+
noBothPropsUsage: 'Do not include both `titleId` and `label` properties. Use `titleId` if the label text is available in the DOM to reference it, otherwise use `label` to provide accessible name explicitly.'
|
|
20
|
+
},
|
|
21
|
+
hasSuggestions: true
|
|
22
|
+
},
|
|
23
|
+
create(context) {
|
|
24
|
+
const contextLocalIdentifier = [];
|
|
25
|
+
return {
|
|
26
|
+
ImportDeclaration(node) {
|
|
27
|
+
if (node.source.value === '@atlaskit/popup') {
|
|
28
|
+
if (node.specifiers.length) {
|
|
29
|
+
const defaultImport = node.specifiers.filter(spec => spec.type === 'ImportDefaultSpecifier');
|
|
30
|
+
if (defaultImport.length) {
|
|
31
|
+
const {
|
|
32
|
+
local
|
|
33
|
+
} = defaultImport[0];
|
|
34
|
+
contextLocalIdentifier.push(local.name);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
JSXElement(node) {
|
|
40
|
+
if (!isNodeOfType(node, 'JSXElement')) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
if (!isNodeOfType(node.openingElement.name, 'JSXIdentifier')) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
const name = node.openingElement.name.name;
|
|
47
|
+
if (contextLocalIdentifier.includes(name)) {
|
|
48
|
+
const componentRoleDialogProp = node.openingElement.attributes.find(attr => isNodeOfType(attr, 'JSXAttribute') && isNodeOfType(attr.name, 'JSXIdentifier') && attr.value && isNodeOfType(attr.value, 'Literal') && attr.name.name === 'role' && attr.value.value === 'dialog');
|
|
49
|
+
const componentLabelProps = node.openingElement.attributes.filter(attr => isNodeOfType(attr, 'JSXAttribute') && isNodeOfType(attr.name, 'JSXIdentifier') && elementsAccessibleNameProps.includes(attr.name.name));
|
|
50
|
+
if (componentLabelProps.length === 1) {
|
|
51
|
+
const prop = componentLabelProps[0];
|
|
52
|
+
if ('value' in prop && prop.value) {
|
|
53
|
+
if (isNodeOfType(prop.value, 'Literal') && !prop.value.value || isNodeOfType(prop.value, 'JSXExpressionContainer') && !prop.value.expression) {
|
|
54
|
+
context.report({
|
|
55
|
+
node: prop,
|
|
56
|
+
messageId: prop.name.name === 'label' ? 'labelPropShouldHaveContents' : 'titleIdShouldHaveValue'
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
} else if (componentLabelProps.length > 1) {
|
|
61
|
+
context.report({
|
|
62
|
+
node: node.openingElement,
|
|
63
|
+
messageId: 'noBothPropsUsage'
|
|
64
|
+
});
|
|
65
|
+
} else {
|
|
66
|
+
if (componentRoleDialogProp) {
|
|
67
|
+
context.report({
|
|
68
|
+
node: node.openingElement,
|
|
69
|
+
messageId: 'missingLabelProp'
|
|
70
|
+
});
|
|
71
|
+
} else {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
export default rule;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
2
|
+
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
3
|
+
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
4
|
+
/**
|
|
5
|
+
* THIS SECTION WAS CREATED VIA CODEGEN DO NOT MODIFY {@see http://go/af-codegen}
|
|
6
|
+
* @codegen <<SignedSource::30c84f908843af1f250860b6f3deeea0>>
|
|
7
|
+
* @codegenId spacing
|
|
8
|
+
* @codegenCommand yarn workspace @atlaskit/eslint-plugin-design-system codegen-token-maps
|
|
9
|
+
* @codegenDependency ../../../tokens/src/artifacts/tokens-raw/atlassian-spacing.tsx <<SignedSource::55622b91aca9b3afac4bce440f222b71>>
|
|
10
|
+
*/
|
|
11
|
+
export var positiveSpaceMap = {
|
|
12
|
+
'0px': 'space.0',
|
|
13
|
+
'2px': 'space.025',
|
|
14
|
+
'4px': 'space.050',
|
|
15
|
+
'6px': 'space.075',
|
|
16
|
+
'8px': 'space.100',
|
|
17
|
+
'12px': 'space.150',
|
|
18
|
+
'16px': 'space.200',
|
|
19
|
+
'20px': 'space.250',
|
|
20
|
+
'24px': 'space.300',
|
|
21
|
+
'32px': 'space.400',
|
|
22
|
+
'40px': 'space.500',
|
|
23
|
+
'48px': 'space.600',
|
|
24
|
+
'64px': 'space.800',
|
|
25
|
+
'80px': 'space.1000'
|
|
26
|
+
};
|
|
27
|
+
export var negativeSpaceMap = {
|
|
28
|
+
'-2px': 'space.negative.025',
|
|
29
|
+
'-4px': 'space.negative.050',
|
|
30
|
+
'-6px': 'space.negative.075',
|
|
31
|
+
'-8px': 'space.negative.100',
|
|
32
|
+
'-12px': 'space.negative.150',
|
|
33
|
+
'-16px': 'space.negative.200',
|
|
34
|
+
'-20px': 'space.negative.250',
|
|
35
|
+
'-24px': 'space.negative.300',
|
|
36
|
+
'-32px': 'space.negative.400'
|
|
37
|
+
};
|
|
38
|
+
export var allSpaceMap = _objectSpread(_objectSpread({}, positiveSpaceMap), negativeSpaceMap);
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* @codegenEnd
|
|
42
|
+
*/
|
|
@@ -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::a1bb0f17560603fa4895326b1d50744e>>
|
|
4
4
|
* @codegenCommand yarn workspace @atlaskit/eslint-plugin-design-system codegen
|
|
5
5
|
*/
|
|
6
6
|
import all from './presets/all.codegen';
|
|
@@ -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::0be7639a95bf4c9bbfe00154d8193477>>
|
|
4
4
|
* @codegenCommand yarn workspace @atlaskit/eslint-plugin-design-system codegen
|
|
5
5
|
*/
|
|
6
6
|
export default {
|
|
@@ -19,7 +19,8 @@ export default {
|
|
|
19
19
|
'@atlaskit/design-system/no-empty-styled-expression': 'warn',
|
|
20
20
|
'@atlaskit/design-system/no-exported-css': 'warn',
|
|
21
21
|
'@atlaskit/design-system/no-exported-keyframes': 'warn',
|
|
22
|
-
'@atlaskit/design-system/no-html-
|
|
22
|
+
'@atlaskit/design-system/no-html-anchor': 'warn',
|
|
23
|
+
'@atlaskit/design-system/no-html-button': 'warn',
|
|
23
24
|
'@atlaskit/design-system/no-invalid-css-map': 'error',
|
|
24
25
|
'@atlaskit/design-system/no-keyframes-tagged-template-expression': 'error',
|
|
25
26
|
'@atlaskit/design-system/no-margin': 'warn',
|
|
@@ -35,6 +36,7 @@ export default {
|
|
|
35
36
|
'@atlaskit/design-system/use-heading': 'warn',
|
|
36
37
|
'@atlaskit/design-system/use-heading-level-in-spotlight-card': 'warn',
|
|
37
38
|
'@atlaskit/design-system/use-href-in-link-item': 'warn',
|
|
39
|
+
'@atlaskit/design-system/use-popup-label': 'warn',
|
|
38
40
|
'@atlaskit/design-system/use-primitives': 'warn',
|
|
39
41
|
'@atlaskit/design-system/use-primitives-text': 'warn',
|
|
40
42
|
'@atlaskit/design-system/use-tokens-space': 'error',
|
|
@@ -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::73a3666b244b58cc221eebcda071161d>>
|
|
4
4
|
* @codegenCommand yarn workspace @atlaskit/eslint-plugin-design-system codegen
|
|
5
5
|
*/
|
|
6
6
|
export default {
|
|
@@ -26,6 +26,7 @@ export default {
|
|
|
26
26
|
'@atlaskit/design-system/use-drawer-label': 'warn',
|
|
27
27
|
'@atlaskit/design-system/use-heading-level-in-spotlight-card': 'warn',
|
|
28
28
|
'@atlaskit/design-system/use-href-in-link-item': 'warn',
|
|
29
|
+
'@atlaskit/design-system/use-popup-label': 'warn',
|
|
29
30
|
'@atlaskit/design-system/use-visually-hidden': 'error'
|
|
30
31
|
}
|
|
31
32
|
};
|
|
@@ -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::9b934590b0ff7880e962fa4dd73bdb0b>>
|
|
4
4
|
* @codegenCommand yarn workspace @atlaskit/eslint-plugin-design-system codegen
|
|
5
5
|
*/
|
|
6
6
|
import consistentCssPropUsage from './consistent-css-prop-usage';
|
|
@@ -16,7 +16,8 @@ import noDirectUseOfWebPlatformDragAndDrop from './no-direct-use-of-web-platform
|
|
|
16
16
|
import noEmptyStyledExpression from './no-empty-styled-expression';
|
|
17
17
|
import noExportedCss from './no-exported-css';
|
|
18
18
|
import noExportedKeyframes from './no-exported-keyframes';
|
|
19
|
-
import
|
|
19
|
+
import noHtmlAnchor from './no-html-anchor';
|
|
20
|
+
import noHtmlButton from './no-html-button';
|
|
20
21
|
import noInvalidCssMap from './no-invalid-css-map';
|
|
21
22
|
import noKeyframesTaggedTemplateExpression from './no-keyframes-tagged-template-expression';
|
|
22
23
|
import noMargin from './no-margin';
|
|
@@ -32,6 +33,7 @@ import useDrawerLabel from './use-drawer-label';
|
|
|
32
33
|
import useHeading from './use-heading';
|
|
33
34
|
import useHeadingLevelInSpotlightCard from './use-heading-level-in-spotlight-card';
|
|
34
35
|
import useHrefInLinkItem from './use-href-in-link-item';
|
|
36
|
+
import usePopupLabel from './use-popup-label';
|
|
35
37
|
import usePrimitives from './use-primitives';
|
|
36
38
|
import usePrimitivesText from './use-primitives-text';
|
|
37
39
|
import useTokensSpace from './use-tokens-space';
|
|
@@ -51,7 +53,8 @@ export default {
|
|
|
51
53
|
'no-empty-styled-expression': noEmptyStyledExpression,
|
|
52
54
|
'no-exported-css': noExportedCss,
|
|
53
55
|
'no-exported-keyframes': noExportedKeyframes,
|
|
54
|
-
'no-html-
|
|
56
|
+
'no-html-anchor': noHtmlAnchor,
|
|
57
|
+
'no-html-button': noHtmlButton,
|
|
55
58
|
'no-invalid-css-map': noInvalidCssMap,
|
|
56
59
|
'no-keyframes-tagged-template-expression': noKeyframesTaggedTemplateExpression,
|
|
57
60
|
'no-margin': noMargin,
|
|
@@ -67,6 +70,7 @@ export default {
|
|
|
67
70
|
'use-heading': useHeading,
|
|
68
71
|
'use-heading-level-in-spotlight-card': useHeadingLevelInSpotlightCard,
|
|
69
72
|
'use-href-in-link-item': useHrefInLinkItem,
|
|
73
|
+
'use-popup-label': usePopupLabel,
|
|
70
74
|
'use-primitives': usePrimitives,
|
|
71
75
|
'use-primitives-text': usePrimitivesText,
|
|
72
76
|
'use-tokens-space': useTokensSpace,
|
|
@@ -0,0 +1,33 @@
|
|
|
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-anchor',
|
|
6
|
+
type: 'suggestion',
|
|
7
|
+
docs: {
|
|
8
|
+
description: 'Discourage direct usage of HTML anchor elements in favor of Atlassian Design System link components.',
|
|
9
|
+
recommended: false,
|
|
10
|
+
severity: 'warn'
|
|
11
|
+
},
|
|
12
|
+
messages: {
|
|
13
|
+
noHtmlAnchor: "This <{{ name }}> should be replaced with a link component from the Atlassian Design System, such as the \"Link\" or \"LinkButton\" component when suitable. For custom links use the \"Anchor\" primitive. ADS links include event tracking, automatic router configuration, ensure accessible implementations, and provide access to ADS styling features like design tokens."
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
create: function create(context) {
|
|
17
|
+
return {
|
|
18
|
+
// transforms styled.<anchor>(...) usages
|
|
19
|
+
CallExpression: function CallExpression(node) {
|
|
20
|
+
StyledComponent.lint(node, {
|
|
21
|
+
context: context
|
|
22
|
+
});
|
|
23
|
+
},
|
|
24
|
+
// transforms <anchor css={...}> usages
|
|
25
|
+
JSXElement: function JSXElement(node) {
|
|
26
|
+
_JSXElement.lint(node, {
|
|
27
|
+
context: context
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
export default rule;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/* eslint-disable @repo/internal/react/require-jsdoc */
|
|
2
|
+
|
|
3
|
+
import * as ast from '../../../../ast-nodes';
|
|
4
|
+
import { isSupportedForLint } from '../supported';
|
|
5
|
+
export var JSXElement = {
|
|
6
|
+
lint: function lint(node, _ref) {
|
|
7
|
+
var context = _ref.context;
|
|
8
|
+
if (!isSupportedForLint(node)) {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
context.report({
|
|
12
|
+
node: node.openingElement,
|
|
13
|
+
messageId: 'noHtmlAnchor',
|
|
14
|
+
data: {
|
|
15
|
+
name: ast.JSXElement.getName(node)
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
};
|
package/dist/esm/rules/no-html-anchor/node-types/styled-component/get-styled-component-call.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { closestOfType, isNodeOfType } from 'eslint-codemod-utils';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Returns a styled component
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export var getStyledComponentCall = function getStyledComponentCall(node) {
|
|
8
|
+
// halts unless we are dealing with a styled component
|
|
9
|
+
if (!isStyledCallExpression(node)) {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
// halts if the component is being exported directly
|
|
13
|
+
if (closestOfType(node, 'ExportNamedDeclaration')) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
var styledComponentVariableRef = node.parent;
|
|
17
|
+
// halts if the styled component is not assigned to a variable immediately
|
|
18
|
+
if (!isNodeOfType(styledComponentVariableRef, 'VariableDeclarator')) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
return styledComponentVariableRef;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Some verbose precondition checks but all it does is check
|
|
26
|
+
* a call expression is of form `styled.a` or `styled2.a`
|
|
27
|
+
*/
|
|
28
|
+
var isStyledCallExpression = function isStyledCallExpression(call) {
|
|
29
|
+
if (!isNodeOfType(call, 'CallExpression')) {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
if (!isNodeOfType(call.callee, 'MemberExpression')) {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
if (!isNodeOfType(call.callee.object, 'Identifier') || !isNodeOfType(call.callee.property, 'Identifier')) {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
if (/^styled2?$/.test(call.callee.object.name)) {
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
return false;
|
|
42
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/* eslint-disable @repo/internal/react/require-jsdoc */
|
|
2
|
+
|
|
3
|
+
import { isNodeOfType } from 'eslint-codemod-utils';
|
|
4
|
+
import { getJsxElementByName } from '../../utils/get-jsx-element-by-name';
|
|
5
|
+
import { isSupportedForLint } from '../supported';
|
|
6
|
+
import { getStyledComponentCall } from './get-styled-component-call';
|
|
7
|
+
export var StyledComponent = {
|
|
8
|
+
lint: function lint(node, _ref) {
|
|
9
|
+
var _getJsxElementByName;
|
|
10
|
+
var context = _ref.context;
|
|
11
|
+
if (!isNodeOfType(node, 'CallExpression') || !isNodeOfType(node.callee, 'MemberExpression') || !isNodeOfType(node.callee.object, 'Identifier') || !isNodeOfType(node.callee.property, 'Identifier')) {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
var styles = getStyledComponentCall(node);
|
|
15
|
+
var elementName = node.callee.property.name;
|
|
16
|
+
if (!styles || !isNodeOfType(styles.id, 'Identifier')) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
var jsxElement = (_getJsxElementByName = getJsxElementByName(styles.id.name, context.getScope())) === null || _getJsxElementByName === void 0 ? void 0 : _getJsxElementByName.parent;
|
|
20
|
+
if (jsxElement && !isSupportedForLint(jsxElement, elementName)) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
context.report({
|
|
24
|
+
node: styles,
|
|
25
|
+
messageId: 'noHtmlAnchor',
|
|
26
|
+
data: {
|
|
27
|
+
name: node.callee.property.name
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { isNodeOfType } from 'eslint-codemod-utils';
|
|
2
|
+
import * as ast from '../../../ast-nodes';
|
|
3
|
+
var supportedElements = [{
|
|
4
|
+
name: 'a'
|
|
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
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
|
|
2
|
+
import { isNodeOfType } from 'eslint-codemod-utils';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Given a component name finds its JSX usage
|
|
6
|
+
*/
|
|
7
|
+
export var getJsxElementByName = function getJsxElementByName(componentName, scope) {
|
|
8
|
+
var _variableDeclaration$;
|
|
9
|
+
var variableDeclaration = scope.variables.find(function (v) {
|
|
10
|
+
return v.name === componentName;
|
|
11
|
+
});
|
|
12
|
+
if (!variableDeclaration) {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// length here should be exactly 2 to indicate only two references:
|
|
17
|
+
// one being the variable declaration itself
|
|
18
|
+
// second being the JSX call site
|
|
19
|
+
// we might consider handling multiple local JSX call sites in the future
|
|
20
|
+
// but "this is good enough for now"™️
|
|
21
|
+
if (variableDeclaration.references.length !== 2) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
var jsxUsage = (_variableDeclaration$ = variableDeclaration.references[1]) === null || _variableDeclaration$ === void 0 ? void 0 : _variableDeclaration$.identifier;
|
|
25
|
+
var _variableDeclaration$2 = variableDeclaration.references.map(function (ref) {
|
|
26
|
+
return ref === null || ref === void 0 ? void 0 : ref.identifier;
|
|
27
|
+
}),
|
|
28
|
+
_variableDeclaration$3 = _slicedToArray(_variableDeclaration$2, 2),
|
|
29
|
+
firstIdentifier = _variableDeclaration$3[0],
|
|
30
|
+
secondIdentifier = _variableDeclaration$3[1];
|
|
31
|
+
// Check if the first reference is a JSXOpeningElement and the second is not or vice versa
|
|
32
|
+
if (isNodeOfType(firstIdentifier, 'JSXIdentifier') && !isNodeOfType(secondIdentifier, 'JSXIdentifier')) {
|
|
33
|
+
jsxUsage = firstIdentifier;
|
|
34
|
+
} else if (isNodeOfType(secondIdentifier, 'JSXIdentifier') && !isNodeOfType(firstIdentifier, 'JSXIdentifier')) {
|
|
35
|
+
jsxUsage = secondIdentifier;
|
|
36
|
+
} else {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
if (!isNodeOfType(jsxUsage, 'JSXIdentifier')) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
var jsxOpeningElement = jsxUsage.parent;
|
|
43
|
+
if (!isNodeOfType(jsxOpeningElement, 'JSXOpeningElement')) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
return jsxOpeningElement;
|
|
47
|
+
};
|