@atlaskit/eslint-plugin-design-system 8.32.0 → 8.32.2
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 +12 -0
- package/constellation/no-styled-tagged-template-expression/usage.mdx +42 -0
- package/dist/cjs/rules/consistent-css-prop-usage/index.js +375 -334
- package/dist/cjs/rules/no-styled-tagged-template-expression/index.js +2 -2
- package/dist/cjs/rules/utils/create-no-tagged-template-expression-rule/index.js +10 -3
- package/dist/cjs/rules/utils/is-supported-import.js +64 -10
- package/dist/es2019/rules/consistent-css-prop-usage/index.js +283 -267
- package/dist/es2019/rules/no-styled-tagged-template-expression/index.js +1 -1
- package/dist/es2019/rules/utils/create-no-tagged-template-expression-rule/index.js +26 -1
- package/dist/es2019/rules/utils/is-supported-import.js +60 -10
- package/dist/esm/rules/consistent-css-prop-usage/index.js +375 -334
- package/dist/esm/rules/no-styled-tagged-template-expression/index.js +1 -1
- package/dist/esm/rules/utils/create-no-tagged-template-expression-rule/index.js +11 -4
- package/dist/esm/rules/utils/is-supported-import.js +63 -9
- package/dist/types/rules/utils/is-supported-import.d.ts +11 -0
- package/dist/types-ts4.5/rules/utils/is-supported-import.d.ts +11 -0
- package/package.json +1 -1
- package/dist/cjs/rules/no-styled-tagged-template-expression/is-styled.js +0 -53
- package/dist/es2019/rules/no-styled-tagged-template-expression/is-styled.js +0 -45
- package/dist/esm/rules/no-styled-tagged-template-expression/is-styled.js +0 -47
- package/dist/types/rules/no-styled-tagged-template-expression/is-styled.d.ts +0 -7
- package/dist/types-ts4.5/rules/no-styled-tagged-template-expression/is-styled.d.ts +0 -7
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createNoTaggedTemplateExpressionRule, noTaggedTemplateExpressionRuleSchema } from '../utils/create-no-tagged-template-expression-rule';
|
|
2
2
|
import { createLintRule } from '../utils/create-rule';
|
|
3
|
-
import { isStyled } from '
|
|
3
|
+
import { isStyled } from '../utils/is-supported-import';
|
|
4
4
|
const rule = createLintRule({
|
|
5
5
|
meta: {
|
|
6
6
|
name: 'no-styled-tagged-template-expression',
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Original source from Compiled https://github.com/atlassian-labs/compiled/blob/master/packages/eslint-plugin/src/utils/create-no-tagged-template-expression-rule/index.ts
|
|
2
2
|
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
3
3
|
|
|
4
|
-
import { getImportSources } from '../is-supported-import';
|
|
4
|
+
import { getImportSources, isStyledComponents } from '../is-supported-import';
|
|
5
5
|
import { generate } from './generate';
|
|
6
6
|
import { getTaggedTemplateExpressionOffset } from './get-tagged-template-expression-offset';
|
|
7
7
|
import { toArguments } from './to-arguments';
|
|
@@ -35,6 +35,7 @@ export const createNoTaggedTemplateExpressionRule = (isUsage, messageId) => cont
|
|
|
35
35
|
if (!isUsage(node.tag, references, importSources)) {
|
|
36
36
|
return;
|
|
37
37
|
}
|
|
38
|
+
const isSC = isStyledComponents(node.tag, references, importSources);
|
|
38
39
|
context.report({
|
|
39
40
|
messageId,
|
|
40
41
|
node,
|
|
@@ -75,6 +76,30 @@ export const createNoTaggedTemplateExpressionRule = (isUsage, messageId) => cont
|
|
|
75
76
|
if (oldCode === newCode) {
|
|
76
77
|
return;
|
|
77
78
|
}
|
|
79
|
+
|
|
80
|
+
// TODO: We might want to similarly disallow `styled.div({ color: props => props.color })` for SC as it's broken too (both type and functionality)
|
|
81
|
+
// Alternatively, autofix it to `styled.div(props => ({ color: props.color }))`?
|
|
82
|
+
if (isSC && /\$\{.*:[\s]*\{/.test(newCode)) {
|
|
83
|
+
/**
|
|
84
|
+
* If we find a variable in a selector when migrating `styled-components` code, we skip it.
|
|
85
|
+
* This is because `styled-components@3.x` does not support the syntax.
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```tsx
|
|
89
|
+
* const Component = styled.div`
|
|
90
|
+
* & + ${Button} { color: red; }
|
|
91
|
+
* `;
|
|
92
|
+
* ```
|
|
93
|
+
* Becomes this code, which is not supported in `styled-components@3.x`:
|
|
94
|
+
* ```tsx
|
|
95
|
+
* const Component = styled.div({
|
|
96
|
+
* [`& + ${Button}`]: {
|
|
97
|
+
* color: 'red',
|
|
98
|
+
* });
|
|
99
|
+
* ```
|
|
100
|
+
*/
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
78
103
|
yield fixer.insertTextBefore(node, newCode);
|
|
79
104
|
yield fixer.remove(node);
|
|
80
105
|
}
|
|
@@ -16,6 +16,21 @@ export const CSS_IN_JS_IMPORTS = {
|
|
|
16
16
|
* By default all known import sources are checked against.
|
|
17
17
|
*/
|
|
18
18
|
export const DEFAULT_IMPORT_SOURCES = Object.values(CSS_IN_JS_IMPORTS);
|
|
19
|
+
const getIdentifierNode = node => {
|
|
20
|
+
let identifierNode = node.type === 'Identifier' ? node : undefined;
|
|
21
|
+
if (!identifierNode) {
|
|
22
|
+
// Handles styled.div`` case
|
|
23
|
+
if (node.type === 'MemberExpression' && node.object.type === 'Identifier') {
|
|
24
|
+
identifierNode = node.object;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Handles styled(Component)`` case
|
|
28
|
+
if (node.type === 'CallExpression' && node.callee.type === 'Identifier') {
|
|
29
|
+
identifierNode = node.callee;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return identifierNode;
|
|
33
|
+
};
|
|
19
34
|
|
|
20
35
|
/**
|
|
21
36
|
* Given the ESLint rule context, extract and parse the value of the importSources rule option.
|
|
@@ -35,7 +50,7 @@ export const getImportSources = context => {
|
|
|
35
50
|
}
|
|
36
51
|
return DEFAULT_IMPORT_SOURCES;
|
|
37
52
|
};
|
|
38
|
-
const isSupportedImportWrapper = functionName => {
|
|
53
|
+
const isSupportedImportWrapper = (functionName, defaultFromImportSources = []) => {
|
|
39
54
|
const checkDefinitionHasImport = (def, importSources) => {
|
|
40
55
|
if (def.type !== 'ImportBinding') {
|
|
41
56
|
return false;
|
|
@@ -43,12 +58,19 @@ const isSupportedImportWrapper = functionName => {
|
|
|
43
58
|
if (!def.parent || !importSources.includes(def.parent.source.value)) {
|
|
44
59
|
return false;
|
|
45
60
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
61
|
+
|
|
62
|
+
// Matches the imported name from a named import
|
|
63
|
+
// import { functionName, functioName as otherName } from 'import-source';
|
|
64
|
+
const isNamedImport = def.node.type === 'ImportSpecifier' && def.node.imported.name === functionName;
|
|
65
|
+
|
|
66
|
+
// Must explicitly match the local name from a default import
|
|
67
|
+
// import functionName from 'import-source';
|
|
68
|
+
const isDefaultImportMatchingLocal = def.node.type === 'ImportDefaultSpecifier' && def.node.local.name === functionName;
|
|
69
|
+
|
|
70
|
+
// Can match any local name from a default import
|
|
71
|
+
// import anything from 'import-source'
|
|
72
|
+
const isKnownDefaultImport = def.node.type === 'ImportDefaultSpecifier' && defaultFromImportSources.includes(def.parent.source.value);
|
|
73
|
+
return isNamedImport || isDefaultImportMatchingLocal || isKnownDefaultImport;
|
|
52
74
|
};
|
|
53
75
|
|
|
54
76
|
/**
|
|
@@ -68,9 +90,10 @@ const isSupportedImportWrapper = functionName => {
|
|
|
68
90
|
* @returns Whether the above conditions are true.
|
|
69
91
|
*/
|
|
70
92
|
const isSupportedImport = (nodeToCheck, referencesInScope, importSources) => {
|
|
71
|
-
|
|
93
|
+
const identifierNode = getIdentifierNode(nodeToCheck);
|
|
94
|
+
return (identifierNode === null || identifierNode === void 0 ? void 0 : identifierNode.type) === 'Identifier' && referencesInScope.some(reference => {
|
|
72
95
|
var _reference$resolved;
|
|
73
|
-
return reference.identifier ===
|
|
96
|
+
return reference.identifier === identifierNode && ((_reference$resolved = reference.resolved) === null || _reference$resolved === void 0 ? void 0 : _reference$resolved.defs.some(def => checkDefinitionHasImport(def, importSources)));
|
|
74
97
|
});
|
|
75
98
|
};
|
|
76
99
|
return isSupportedImport;
|
|
@@ -83,4 +106,31 @@ export const isCss = isSupportedImportWrapper('css');
|
|
|
83
106
|
export const isCxFunction = isSupportedImportWrapper('cx');
|
|
84
107
|
export const isCssMap = isSupportedImportWrapper('cssMap');
|
|
85
108
|
export const isKeyframes = isSupportedImportWrapper('keyframes');
|
|
86
|
-
|
|
109
|
+
// `styled` is also the explicit default of `styled-components` and `@emotion/styled`, so we also match on default imports generally
|
|
110
|
+
export const isStyled = isSupportedImportWrapper('styled', ['styled-components', '@emotion/styled']);
|
|
111
|
+
export const isImportedFrom = (moduleName, exactMatch = true) => (nodeToCheck, referencesInScope, importSources) => {
|
|
112
|
+
if (!importSources.includes(moduleName)) {
|
|
113
|
+
// Don't go through the trouble of checking the import sources does not include this
|
|
114
|
+
// We'll assume this is skipped elsewhere.
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
const identifierNode = getIdentifierNode(nodeToCheck);
|
|
118
|
+
return (identifierNode === null || identifierNode === void 0 ? void 0 : identifierNode.type) === 'Identifier' && referencesInScope.some(reference => {
|
|
119
|
+
var _reference$resolved2;
|
|
120
|
+
return reference.identifier === identifierNode && ((_reference$resolved2 = reference.resolved) === null || _reference$resolved2 === void 0 ? void 0 : _reference$resolved2.defs.some(def => {
|
|
121
|
+
var _def$parent, _String, _def$parent2;
|
|
122
|
+
return def.type === 'ImportBinding' && (((_def$parent = def.parent) === null || _def$parent === void 0 ? void 0 : _def$parent.source.value) === moduleName || !exactMatch && ((_String = String((_def$parent2 = def.parent) === null || _def$parent2 === void 0 ? void 0 : _def$parent2.source.value)) === null || _String === void 0 ? void 0 : _String.startsWith(moduleName)));
|
|
123
|
+
}));
|
|
124
|
+
});
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Determine if this node is specifically from a `'styled-components'` import.
|
|
129
|
+
* This is because `styled-components@3.4` APIs are not consistent with Emotion and Compiled,
|
|
130
|
+
* we need to handle them differently in a few scenarios.
|
|
131
|
+
*
|
|
132
|
+
* This can be cleaned up when `'styled-components'` is no longer a valid ImportSource.
|
|
133
|
+
*/
|
|
134
|
+
export const isStyledComponents = isImportedFrom('styled-components');
|
|
135
|
+
export const isCompiled = isImportedFrom('@compiled/', false);
|
|
136
|
+
export const isEmotion = isImportedFrom('@emotion/', false);
|