@atlaskit/eslint-plugin-design-system 8.25.2 → 8.26.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 +17 -0
- package/README.md +4 -0
- package/constellation/index/usage.mdx +362 -0
- package/dist/cjs/presets/all.codegen.js +5 -1
- package/dist/cjs/presets/recommended.codegen.js +5 -1
- package/dist/cjs/rules/index.codegen.js +9 -1
- package/dist/cjs/rules/no-empty-styled-expression/index.js +75 -0
- package/dist/cjs/rules/no-exported-css/index.js +37 -0
- package/dist/cjs/rules/no-exported-keyframes/index.js +37 -0
- package/dist/cjs/rules/no-invalid-css-map/index.js +102 -0
- package/dist/cjs/rules/no-invalid-css-map/utils.js +193 -0
- package/dist/cjs/rules/utils/create-no-exported-rule/check-if-supported-export.js +158 -0
- package/dist/cjs/rules/utils/create-no-exported-rule/is-styled-component.js +84 -0
- package/dist/cjs/rules/utils/create-no-exported-rule/main.js +66 -0
- package/dist/cjs/rules/utils/is-supported-import.js +51 -15
- package/dist/es2019/presets/all.codegen.js +5 -1
- package/dist/es2019/presets/recommended.codegen.js +5 -1
- package/dist/es2019/rules/index.codegen.js +9 -1
- package/dist/es2019/rules/no-empty-styled-expression/index.js +65 -0
- package/dist/es2019/rules/no-exported-css/index.js +31 -0
- package/dist/es2019/rules/no-exported-keyframes/index.js +31 -0
- package/dist/es2019/rules/no-invalid-css-map/index.js +95 -0
- package/dist/es2019/rules/no-invalid-css-map/utils.js +134 -0
- package/dist/es2019/rules/utils/create-no-exported-rule/check-if-supported-export.js +142 -0
- package/dist/es2019/rules/utils/create-no-exported-rule/is-styled-component.js +74 -0
- package/dist/es2019/rules/utils/create-no-exported-rule/main.js +59 -0
- package/dist/es2019/rules/utils/is-supported-import.js +48 -14
- package/dist/esm/presets/all.codegen.js +5 -1
- package/dist/esm/presets/recommended.codegen.js +5 -1
- package/dist/esm/rules/index.codegen.js +9 -1
- package/dist/esm/rules/no-empty-styled-expression/index.js +68 -0
- package/dist/esm/rules/no-exported-css/index.js +31 -0
- package/dist/esm/rules/no-exported-keyframes/index.js +31 -0
- package/dist/esm/rules/no-invalid-css-map/index.js +96 -0
- package/dist/esm/rules/no-invalid-css-map/utils.js +186 -0
- package/dist/esm/rules/utils/create-no-exported-rule/check-if-supported-export.js +151 -0
- package/dist/esm/rules/utils/create-no-exported-rule/is-styled-component.js +78 -0
- package/dist/esm/rules/utils/create-no-exported-rule/main.js +60 -0
- package/dist/esm/rules/utils/is-supported-import.js +49 -14
- package/dist/types/index.codegen.d.ts +8 -0
- package/dist/types/presets/all.codegen.d.ts +5 -1
- package/dist/types/presets/recommended.codegen.d.ts +5 -1
- package/dist/types/rules/index.codegen.d.ts +4 -0
- package/dist/types/rules/no-empty-styled-expression/index.d.ts +3 -0
- package/dist/types/rules/no-exported-css/index.d.ts +3 -0
- package/dist/types/rules/no-exported-keyframes/index.d.ts +3 -0
- package/dist/types/rules/no-invalid-css-map/index.d.ts +3 -0
- package/dist/types/rules/no-invalid-css-map/utils.d.ts +14 -0
- package/dist/types/rules/utils/create-no-exported-rule/check-if-supported-export.d.ts +15 -0
- package/dist/types/rules/utils/create-no-exported-rule/is-styled-component.d.ts +14 -0
- package/dist/types/rules/utils/create-no-exported-rule/main.d.ts +19 -0
- package/dist/types/rules/utils/create-rule.d.ts +1 -1
- package/dist/types/rules/utils/is-supported-import.d.ts +25 -8
- package/dist/types-ts4.5/index.codegen.d.ts +8 -0
- package/dist/types-ts4.5/presets/all.codegen.d.ts +5 -1
- package/dist/types-ts4.5/presets/recommended.codegen.d.ts +5 -1
- package/dist/types-ts4.5/rules/index.codegen.d.ts +4 -0
- package/dist/types-ts4.5/rules/no-empty-styled-expression/index.d.ts +3 -0
- package/dist/types-ts4.5/rules/no-exported-css/index.d.ts +3 -0
- package/dist/types-ts4.5/rules/no-exported-keyframes/index.d.ts +3 -0
- package/dist/types-ts4.5/rules/no-invalid-css-map/index.d.ts +3 -0
- package/dist/types-ts4.5/rules/no-invalid-css-map/utils.d.ts +14 -0
- package/dist/types-ts4.5/rules/utils/create-no-exported-rule/check-if-supported-export.d.ts +15 -0
- package/dist/types-ts4.5/rules/utils/create-no-exported-rule/is-styled-component.d.ts +14 -0
- package/dist/types-ts4.5/rules/utils/create-no-exported-rule/main.d.ts +19 -0
- package/dist/types-ts4.5/rules/utils/create-rule.d.ts +1 -1
- package/dist/types-ts4.5/rules/utils/is-supported-import.d.ts +25 -8
- package/package.json +1 -1
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { isNodeOfType } from 'eslint-codemod-utils';
|
|
2
|
+
/**
|
|
3
|
+
* Given a list of node, find and return the callee of the first Compiled or styled-components `styled` function call found in the list.
|
|
4
|
+
*
|
|
5
|
+
* For example, given `styled.div({ ... })`, we return the node corresponding to the
|
|
6
|
+
* `styled.div` part. Alternatively, given `styled(button)(style)`, we return the `styled`
|
|
7
|
+
* part.
|
|
8
|
+
*
|
|
9
|
+
* @param nodes
|
|
10
|
+
* @returns The callee of the first `styled` function call found.
|
|
11
|
+
*/
|
|
12
|
+
const findNode = nodes => {
|
|
13
|
+
const node = nodes.find(n => n.type === 'TaggedTemplateExpression' || n.type === 'CallExpression');
|
|
14
|
+
if (!node) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
if (node.type === 'CallExpression') {
|
|
18
|
+
// Eg. const Component = styled.button(style)
|
|
19
|
+
if (node.callee.type === 'MemberExpression') {
|
|
20
|
+
return node.callee;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Eg. const Component = styled(button)(style)
|
|
24
|
+
if (node.callee.type === 'CallExpression' && node.callee.callee.type === 'Identifier') {
|
|
25
|
+
return node.callee.callee;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Eg. const Component = styled.div`${styles}`;
|
|
30
|
+
if (node.type === 'TaggedTemplateExpression' && node.tag.type === 'MemberExpression') {
|
|
31
|
+
return node.tag;
|
|
32
|
+
}
|
|
33
|
+
return;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Given a rule, return the local name used to import the `styled` API. (for Compiled or styled-components).
|
|
38
|
+
*
|
|
39
|
+
* @param context Rule context.
|
|
40
|
+
* @returns The local name used to import the `styled` API.
|
|
41
|
+
*/
|
|
42
|
+
const getStyledImportSpecifierName = (context, importSources) => {
|
|
43
|
+
var _supportedImports$0$s;
|
|
44
|
+
const isSupportedImport = node => {
|
|
45
|
+
return isNodeOfType(node, 'ImportDeclaration') && typeof node.source.value === 'string' && importSources.includes(node.source.value);
|
|
46
|
+
};
|
|
47
|
+
const source = context.getSourceCode();
|
|
48
|
+
const supportedImports = source.ast.body.filter(isSupportedImport);
|
|
49
|
+
return (_supportedImports$0$s = supportedImports[0].specifiers.find(spec => spec.type === 'ImportSpecifier' && spec.imported.name === 'styled')) === null || _supportedImports$0$s === void 0 ? void 0 : _supportedImports$0$s.local.name;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Returns whether the node is a usage of the `styled` API in the libraries we support.
|
|
54
|
+
*
|
|
55
|
+
* @param nodes Nodes to check.
|
|
56
|
+
* @param context Rule context.
|
|
57
|
+
* @param importSources A list of libraries we support.
|
|
58
|
+
* @returns Whether the node is a usage of the `styled` API.
|
|
59
|
+
*/
|
|
60
|
+
export const isStyledComponent = (nodes, context, importSources) => {
|
|
61
|
+
const node = findNode(nodes);
|
|
62
|
+
if (!node) {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
const styledImportSpecifierName = getStyledImportSpecifierName(context, importSources);
|
|
66
|
+
if (styledImportSpecifierName) {
|
|
67
|
+
if (node.type === 'Identifier') {
|
|
68
|
+
return node.name === styledImportSpecifierName;
|
|
69
|
+
} else {
|
|
70
|
+
return node.object.type === 'Identifier' && node.object.name === styledImportSpecifierName;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return false;
|
|
74
|
+
};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { getImportSources } from '../is-supported-import';
|
|
2
|
+
import { checkIfSupportedExport } from './check-if-supported-export';
|
|
3
|
+
/**
|
|
4
|
+
* Creates a new ESLint rule for banning exporting certain function calls, e.g.
|
|
5
|
+
* `css` and `keyframes`.
|
|
6
|
+
*
|
|
7
|
+
* Copied from the `utils/create-no-exported-rule/` folder in @compiled/eslint-plugin.
|
|
8
|
+
*
|
|
9
|
+
* Requires an importSources option defined on the rule, which is used to define additional
|
|
10
|
+
* packages which should be checked as part of this rule.
|
|
11
|
+
*
|
|
12
|
+
* @param isUsage A function that checks whether the current node matches the desired
|
|
13
|
+
* function call to check.
|
|
14
|
+
* @param messageId The ESLint error message to use for lint violations.
|
|
15
|
+
* @returns An eslint rule.
|
|
16
|
+
*/
|
|
17
|
+
export const createNoExportedRule = (isUsage, messageId) => context => {
|
|
18
|
+
const importSources = getImportSources(context);
|
|
19
|
+
const {
|
|
20
|
+
text
|
|
21
|
+
} = context.getSourceCode();
|
|
22
|
+
if (importSources.every(importSource => !text.includes(importSource))) {
|
|
23
|
+
return {};
|
|
24
|
+
}
|
|
25
|
+
return {
|
|
26
|
+
CallExpression(node) {
|
|
27
|
+
const {
|
|
28
|
+
references
|
|
29
|
+
} = context.getScope();
|
|
30
|
+
if (!isUsage(node.callee, references, importSources)) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const state = checkIfSupportedExport(context, node, importSources);
|
|
34
|
+
if (!state.isExport) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
context.report({
|
|
38
|
+
messageId,
|
|
39
|
+
node: state.node
|
|
40
|
+
});
|
|
41
|
+
},
|
|
42
|
+
TaggedTemplateExpression(node) {
|
|
43
|
+
const {
|
|
44
|
+
references
|
|
45
|
+
} = context.getScope();
|
|
46
|
+
if (!isUsage(node.tag, references, importSources)) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
const state = checkIfSupportedExport(context, node, importSources);
|
|
50
|
+
if (!state.isExport) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
context.report({
|
|
54
|
+
messageId,
|
|
55
|
+
node: state.node
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
};
|
|
@@ -8,31 +8,64 @@ export const CSS_IN_JS_IMPORTS = {
|
|
|
8
8
|
atlaskitCss: '@atlaskit/css'
|
|
9
9
|
};
|
|
10
10
|
|
|
11
|
-
//
|
|
11
|
+
// A CSS-in-JS library an import of a valid css, cx, cssMap, etc.
|
|
12
12
|
// function might originate from, e.g. @compiled/react, @emotion/core.
|
|
13
|
+
// All ESLint rules originating from `@compiled/eslint-plugin` should apply to these libraries.
|
|
14
|
+
export const DEFAULT_IMPORT_SOURCES = [CSS_IN_JS_IMPORTS.compiled, CSS_IN_JS_IMPORTS.atlaskitCss];
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Given the ESLint rule context, extract and parse the value of the importSources rule option.
|
|
18
|
+
* The importSources option is used to define additional libraries for which an ESLint rule
|
|
19
|
+
* should apply to.
|
|
20
|
+
*
|
|
21
|
+
* Note that `@compiled/react` and `@atlaskit/css` are always included in importSources, regardless
|
|
22
|
+
* of what importSources is configured to by the user.
|
|
23
|
+
*
|
|
24
|
+
* @param context The rule context.
|
|
25
|
+
* @returns An array of strings representing what CSS-in-JS packages that should be checked, based
|
|
26
|
+
* on the rule options configuration.
|
|
27
|
+
*/
|
|
28
|
+
export const getImportSources = context => {
|
|
29
|
+
const options = context.options;
|
|
30
|
+
if (!options.length) {
|
|
31
|
+
return DEFAULT_IMPORT_SOURCES;
|
|
32
|
+
}
|
|
33
|
+
if (options[0].importSources && Array.isArray(options[0].importSources)) {
|
|
34
|
+
return [...DEFAULT_IMPORT_SOURCES, ...options[0].importSources];
|
|
35
|
+
}
|
|
36
|
+
return DEFAULT_IMPORT_SOURCES;
|
|
37
|
+
};
|
|
13
38
|
const isSupportedImportWrapper = functionName => {
|
|
14
|
-
// This will need to be extended to support default imports once we start
|
|
15
|
-
// checking cases like `import css from '@emotion/css'`
|
|
16
39
|
const checkDefinitionHasImport = (def, importSources) => {
|
|
17
|
-
|
|
18
|
-
|
|
40
|
+
if (def.type !== 'ImportBinding') {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
if (!def.parent || !importSources.includes(def.parent.source.value)) {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
return (
|
|
47
|
+
// import { functionName } from 'import-source';
|
|
48
|
+
def.node.type === 'ImportSpecifier' && def.node.imported.name === functionName ||
|
|
49
|
+
// import functionName from 'import-source';
|
|
50
|
+
def.node.type === 'ImportDefaultSpecifier' && def.node.local.name === functionName
|
|
51
|
+
);
|
|
19
52
|
};
|
|
20
53
|
|
|
21
54
|
/**
|
|
22
55
|
* Checks whether:
|
|
23
56
|
*
|
|
24
|
-
* 1.
|
|
57
|
+
* 1. A function name `nodeToCheck` matches the name of the function we
|
|
25
58
|
* want to check for (e.g. `cx`, `css`, `cssMap`, or `keyframes`), and
|
|
26
|
-
* 2.
|
|
59
|
+
* 2. Whether `nodeToCheck` originates from one of the libraries listed
|
|
27
60
|
* in `importSources`.
|
|
28
61
|
*
|
|
29
|
-
* @param nodeToCheck
|
|
30
|
-
* @param referencesInScope
|
|
62
|
+
* @param nodeToCheck The function callee we are checking (e.g. The `css` in `css()`).
|
|
63
|
+
* @param referencesInScope List of references that are in scope. We'll use this
|
|
31
64
|
* to check where the function callee is imported from.
|
|
32
|
-
* @param importSources
|
|
33
|
-
* comes from
|
|
65
|
+
* @param importSources List of libraries that we want to ensure `nodeToCheck`
|
|
66
|
+
* comes from.
|
|
34
67
|
*
|
|
35
|
-
* @returns
|
|
68
|
+
* @returns Whether the above conditions are true.
|
|
36
69
|
*/
|
|
37
70
|
const isSupportedImport = (nodeToCheck, referencesInScope, importSources) => {
|
|
38
71
|
return nodeToCheck.type === 'Identifier' && referencesInScope.some(reference => {
|
|
@@ -48,5 +81,6 @@ const isSupportedImportWrapper = functionName => {
|
|
|
48
81
|
//
|
|
49
82
|
export const isCss = isSupportedImportWrapper('css');
|
|
50
83
|
export const isCxFunction = isSupportedImportWrapper('cx');
|
|
51
|
-
|
|
52
|
-
|
|
84
|
+
export const isCssMap = isSupportedImportWrapper('cssMap');
|
|
85
|
+
export const isKeyframes = isSupportedImportWrapper('keyframes');
|
|
86
|
+
export const isStyled = isSupportedImportWrapper('styled');
|
|
@@ -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::914085544778f4543f43e3e30d0982e0>>
|
|
4
4
|
* @codegenCommand yarn workspace @atlaskit/eslint-plugin-design-system codegen
|
|
5
5
|
*/
|
|
6
6
|
export default {
|
|
@@ -16,6 +16,10 @@ export default {
|
|
|
16
16
|
'@atlaskit/design-system/no-deprecated-apis': 'error',
|
|
17
17
|
'@atlaskit/design-system/no-deprecated-design-token-usage': 'warn',
|
|
18
18
|
'@atlaskit/design-system/no-deprecated-imports': 'error',
|
|
19
|
+
'@atlaskit/design-system/no-empty-styled-expression': 'warn',
|
|
20
|
+
'@atlaskit/design-system/no-exported-css': 'warn',
|
|
21
|
+
'@atlaskit/design-system/no-exported-keyframes': 'warn',
|
|
22
|
+
'@atlaskit/design-system/no-invalid-css-map': 'error',
|
|
19
23
|
'@atlaskit/design-system/no-margin': 'warn',
|
|
20
24
|
'@atlaskit/design-system/no-nested-styles': 'error',
|
|
21
25
|
'@atlaskit/design-system/no-physical-properties': '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::577269c832952ce359cde6a50f26f4e0>>
|
|
4
4
|
* @codegenCommand yarn workspace @atlaskit/eslint-plugin-design-system codegen
|
|
5
5
|
*/
|
|
6
6
|
export default {
|
|
@@ -14,6 +14,10 @@ export default {
|
|
|
14
14
|
'@atlaskit/design-system/no-deprecated-apis': 'error',
|
|
15
15
|
'@atlaskit/design-system/no-deprecated-design-token-usage': 'warn',
|
|
16
16
|
'@atlaskit/design-system/no-deprecated-imports': 'error',
|
|
17
|
+
'@atlaskit/design-system/no-empty-styled-expression': 'warn',
|
|
18
|
+
'@atlaskit/design-system/no-exported-css': 'warn',
|
|
19
|
+
'@atlaskit/design-system/no-exported-keyframes': 'warn',
|
|
20
|
+
'@atlaskit/design-system/no-invalid-css-map': 'error',
|
|
17
21
|
'@atlaskit/design-system/no-nested-styles': 'error',
|
|
18
22
|
'@atlaskit/design-system/no-unsafe-design-token-usage': 'error',
|
|
19
23
|
'@atlaskit/design-system/no-unsafe-style-overrides': 'warn',
|
|
@@ -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::0a2d88c9772eb438048415f13550f592>>
|
|
4
4
|
* @codegenCommand yarn workspace @atlaskit/eslint-plugin-design-system codegen
|
|
5
5
|
*/
|
|
6
6
|
import consistentCssPropUsage from './consistent-css-prop-usage';
|
|
@@ -13,6 +13,10 @@ import noCssTaggedTemplateExpression from './no-css-tagged-template-expression';
|
|
|
13
13
|
import noDeprecatedApis from './no-deprecated-apis';
|
|
14
14
|
import noDeprecatedDesignTokenUsage from './no-deprecated-design-token-usage';
|
|
15
15
|
import noDeprecatedImports from './no-deprecated-imports';
|
|
16
|
+
import noEmptyStyledExpression from './no-empty-styled-expression';
|
|
17
|
+
import noExportedCss from './no-exported-css';
|
|
18
|
+
import noExportedKeyframes from './no-exported-keyframes';
|
|
19
|
+
import noInvalidCssMap from './no-invalid-css-map';
|
|
16
20
|
import noMargin from './no-margin';
|
|
17
21
|
import noNestedStyles from './no-nested-styles';
|
|
18
22
|
import noPhysicalProperties from './no-physical-properties';
|
|
@@ -37,6 +41,10 @@ export default {
|
|
|
37
41
|
'no-deprecated-apis': noDeprecatedApis,
|
|
38
42
|
'no-deprecated-design-token-usage': noDeprecatedDesignTokenUsage,
|
|
39
43
|
'no-deprecated-imports': noDeprecatedImports,
|
|
44
|
+
'no-empty-styled-expression': noEmptyStyledExpression,
|
|
45
|
+
'no-exported-css': noExportedCss,
|
|
46
|
+
'no-exported-keyframes': noExportedKeyframes,
|
|
47
|
+
'no-invalid-css-map': noInvalidCssMap,
|
|
40
48
|
'no-margin': noMargin,
|
|
41
49
|
'no-nested-styles': noNestedStyles,
|
|
42
50
|
'no-physical-properties': noPhysicalProperties,
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
|
|
2
|
+
import { createLintRule } from '../utils/create-rule';
|
|
3
|
+
import { getImportSources, isStyled } from '../utils/is-supported-import';
|
|
4
|
+
var isEmptyStyledExpression = function isEmptyStyledExpression(node) {
|
|
5
|
+
var _node$arguments = _slicedToArray(node.arguments, 1),
|
|
6
|
+
firstArg = _node$arguments[0];
|
|
7
|
+
if (node.arguments.length === 0) {
|
|
8
|
+
return true;
|
|
9
|
+
} else if (node.arguments.length === 1 && (firstArg === null || firstArg === void 0 ? void 0 : firstArg.type) === 'ArrayExpression') {
|
|
10
|
+
return firstArg.elements.length === 0;
|
|
11
|
+
} else if (node.arguments.length === 1 && (firstArg === null || firstArg === void 0 ? void 0 : firstArg.type) === 'ObjectExpression') {
|
|
12
|
+
return firstArg.properties.length === 0;
|
|
13
|
+
}
|
|
14
|
+
return false;
|
|
15
|
+
};
|
|
16
|
+
var createNoEmptyStyledExpressionRule = function createNoEmptyStyledExpressionRule(isEmptyStyledExpression, messageId) {
|
|
17
|
+
return function (context) {
|
|
18
|
+
var importSources = getImportSources(context);
|
|
19
|
+
return {
|
|
20
|
+
'CallExpression[callee.type="MemberExpression"]': function CallExpressionCalleeTypeMemberExpression(node) {
|
|
21
|
+
var _context$getScope = context.getScope(),
|
|
22
|
+
references = _context$getScope.references;
|
|
23
|
+
|
|
24
|
+
// If we have styled.div(...), make sure `callee` only refers to the
|
|
25
|
+
// `styled` part instead of the whole `styled.div` expression.
|
|
26
|
+
var callee = node.callee.type === 'MemberExpression' ? node.callee.object : node.callee;
|
|
27
|
+
if (!isStyled(callee, references, importSources)) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
if (!isEmptyStyledExpression(node)) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
context.report({
|
|
34
|
+
messageId: messageId,
|
|
35
|
+
node: node
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
var noEmptyStyledExpressionRule = createLintRule({
|
|
42
|
+
meta: {
|
|
43
|
+
name: 'no-empty-styled-expression',
|
|
44
|
+
docs: {
|
|
45
|
+
description: 'Forbids any styled expression to be used when passing empty arguments to styled.div() (or other JSX elements).',
|
|
46
|
+
recommended: true,
|
|
47
|
+
severity: 'warn'
|
|
48
|
+
},
|
|
49
|
+
messages: {
|
|
50
|
+
unexpected: 'Found an empty expression, or empty object argument passed to `styled` function call. This unnecessarily causes a major performance penalty - please use a plain JSX element or a React fragment instead (e.g. `<div>Hello</div>` or `<>Hello</>`).'
|
|
51
|
+
},
|
|
52
|
+
type: 'problem',
|
|
53
|
+
schema: [{
|
|
54
|
+
type: 'object',
|
|
55
|
+
properties: {
|
|
56
|
+
importSources: {
|
|
57
|
+
type: 'array',
|
|
58
|
+
items: [{
|
|
59
|
+
type: 'string'
|
|
60
|
+
}]
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
additionalProperties: false
|
|
64
|
+
}]
|
|
65
|
+
},
|
|
66
|
+
create: createNoEmptyStyledExpressionRule(isEmptyStyledExpression, 'unexpected')
|
|
67
|
+
});
|
|
68
|
+
export default noEmptyStyledExpressionRule;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { createNoExportedRule } from '../utils/create-no-exported-rule/main';
|
|
2
|
+
import { createLintRule } from '../utils/create-rule';
|
|
3
|
+
import { isCss } from '../utils/is-supported-import';
|
|
4
|
+
var noExportedCssRule = createLintRule({
|
|
5
|
+
meta: {
|
|
6
|
+
name: 'no-exported-css',
|
|
7
|
+
type: 'problem',
|
|
8
|
+
docs: {
|
|
9
|
+
description: 'Forbid exporting `css` function calls. Exporting `css` function calls can result in unexpected behaviour at runtime, and is not statically analysable.',
|
|
10
|
+
recommended: true,
|
|
11
|
+
severity: 'warn'
|
|
12
|
+
},
|
|
13
|
+
messages: {
|
|
14
|
+
unexpected: "`css` can't be exported - this will cause unexpected behaviour at runtime. Instead, please move your `css(...)` code to the same file where these styles are being used."
|
|
15
|
+
},
|
|
16
|
+
schema: [{
|
|
17
|
+
type: 'object',
|
|
18
|
+
properties: {
|
|
19
|
+
importSources: {
|
|
20
|
+
type: 'array',
|
|
21
|
+
items: [{
|
|
22
|
+
type: 'string'
|
|
23
|
+
}]
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
additionalProperties: false
|
|
27
|
+
}]
|
|
28
|
+
},
|
|
29
|
+
create: createNoExportedRule(isCss, 'unexpected')
|
|
30
|
+
});
|
|
31
|
+
export default noExportedCssRule;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { createNoExportedRule } from '../utils/create-no-exported-rule/main';
|
|
2
|
+
import { createLintRule } from '../utils/create-rule';
|
|
3
|
+
import { isKeyframes } from '../utils/is-supported-import';
|
|
4
|
+
var noExportedKeyframesRule = createLintRule({
|
|
5
|
+
meta: {
|
|
6
|
+
name: 'no-exported-keyframes',
|
|
7
|
+
type: 'problem',
|
|
8
|
+
docs: {
|
|
9
|
+
description: 'Forbid exporting `keyframes` function calls. Exporting `css` function calls can result in unexpected behaviour at runtime, and is not statically analysable.',
|
|
10
|
+
recommended: true,
|
|
11
|
+
severity: 'warn'
|
|
12
|
+
},
|
|
13
|
+
messages: {
|
|
14
|
+
unexpected: "`keyframes` can't be exported - this will cause unexpected behaviour at runtime. Instead, please move your `keyframes(...)` code to the same file where these styles are being used."
|
|
15
|
+
},
|
|
16
|
+
schema: [{
|
|
17
|
+
type: 'object',
|
|
18
|
+
properties: {
|
|
19
|
+
importSources: {
|
|
20
|
+
type: 'array',
|
|
21
|
+
items: [{
|
|
22
|
+
type: 'string'
|
|
23
|
+
}]
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
additionalProperties: false
|
|
27
|
+
}]
|
|
28
|
+
},
|
|
29
|
+
create: createNoExportedRule(isKeyframes, 'unexpected')
|
|
30
|
+
});
|
|
31
|
+
export default noExportedKeyframesRule;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { checkIfSupportedExport } from '../utils/create-no-exported-rule/check-if-supported-export';
|
|
2
|
+
import { createLintRule } from '../utils/create-rule';
|
|
3
|
+
import { CSS_IN_JS_IMPORTS, isCssMap } from '../utils/is-supported-import';
|
|
4
|
+
import { CssMapObjectChecker, getCssMapObject } from './utils';
|
|
5
|
+
var IMPORT_SOURCES = [CSS_IN_JS_IMPORTS.compiled, CSS_IN_JS_IMPORTS.atlaskitCss];
|
|
6
|
+
var reportIfExported = function reportIfExported(node, context) {
|
|
7
|
+
var state = checkIfSupportedExport(context, node, IMPORT_SOURCES);
|
|
8
|
+
if (!state.isExport) {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
context.report({
|
|
12
|
+
messageId: 'noExportedCssMap',
|
|
13
|
+
node: state.node
|
|
14
|
+
});
|
|
15
|
+
};
|
|
16
|
+
var reportIfNotTopLevelScope = function reportIfNotTopLevelScope(node, context) {
|
|
17
|
+
// Treat `export` keyword as valid because the reportIfExported function already handles those
|
|
18
|
+
var validTypes = ['ExportDefaultDeclaration', 'ExportNamedDeclaration', 'Program', 'VariableDeclaration', 'VariableDeclarator'];
|
|
19
|
+
var parentNode = node.parent;
|
|
20
|
+
while (parentNode) {
|
|
21
|
+
if (!validTypes.includes(parentNode.type)) {
|
|
22
|
+
context.report({
|
|
23
|
+
node: node,
|
|
24
|
+
messageId: 'mustBeTopLevelScope'
|
|
25
|
+
});
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
parentNode = parentNode.parent;
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
var createCssMapRule = function createCssMapRule(context) {
|
|
32
|
+
var _context$getSourceCod = context.getSourceCode(),
|
|
33
|
+
text = _context$getSourceCod.text;
|
|
34
|
+
if (IMPORT_SOURCES.every(function (importSource) {
|
|
35
|
+
return !text.includes(importSource);
|
|
36
|
+
})) {
|
|
37
|
+
return {};
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
CallExpression: function CallExpression(node) {
|
|
41
|
+
var references = context.getScope().references;
|
|
42
|
+
if (!isCssMap(node.callee, references, IMPORT_SOURCES)) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
reportIfExported(node, context);
|
|
46
|
+
reportIfNotTopLevelScope(node, context);
|
|
47
|
+
var cssMapObject = getCssMapObject(node);
|
|
48
|
+
if (!cssMapObject) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
var cssMapObjectChecker = new CssMapObjectChecker(cssMapObject, context);
|
|
52
|
+
cssMapObjectChecker.run();
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
var noInvalidCssMapRule = createLintRule({
|
|
57
|
+
meta: {
|
|
58
|
+
name: 'no-invalid-css-map',
|
|
59
|
+
docs: {
|
|
60
|
+
description: "Checks the validity of a CSS map created through cssMap. This is intended to be used alongside TypeScript's type-checking.",
|
|
61
|
+
recommended: true,
|
|
62
|
+
severity: 'error'
|
|
63
|
+
},
|
|
64
|
+
messages: {
|
|
65
|
+
mustBeTopLevelScope: 'cssMap must only be used in the top-most scope of the module.',
|
|
66
|
+
noNonStaticallyEvaluable: 'Cannot statically evaluate the value of this variable. Values used in the cssMap function call should have a value evaluable at build time.',
|
|
67
|
+
noExportedCssMap: 'cssMap usages cannot be exported.',
|
|
68
|
+
noInlineFunctions: 'Cannot use functions as values in cssMap - values must only be statically evaluable values (e.g. strings, numbers).',
|
|
69
|
+
noFunctionCalls: 'Cannot call external functions in cssMap - values must only be statically evaluable values (e.g. strings, numbers).',
|
|
70
|
+
noSpreadElement: 'Cannot use the spread operator in cssMap.'
|
|
71
|
+
},
|
|
72
|
+
schema: [{
|
|
73
|
+
type: 'object',
|
|
74
|
+
properties: {
|
|
75
|
+
allowedFunctionCalls: {
|
|
76
|
+
type: 'array',
|
|
77
|
+
items: {
|
|
78
|
+
type: 'array',
|
|
79
|
+
minItems: 2,
|
|
80
|
+
maxItems: 2,
|
|
81
|
+
items: [{
|
|
82
|
+
type: 'string'
|
|
83
|
+
}, {
|
|
84
|
+
type: 'string'
|
|
85
|
+
}]
|
|
86
|
+
},
|
|
87
|
+
uniqueItems: true
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
additionalProperties: false
|
|
91
|
+
}],
|
|
92
|
+
type: 'problem'
|
|
93
|
+
},
|
|
94
|
+
create: createCssMapRule
|
|
95
|
+
});
|
|
96
|
+
export default noInvalidCssMapRule;
|