@atlaskit/eslint-plugin-design-system 10.8.2 → 10.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 +17 -0
- package/README.md +1 -0
- package/constellation/consistent-css-prop-usage/usage.mdx +9 -0
- package/constellation/index/usage.mdx +1 -0
- package/constellation/no-custom-icons/usage.mdx +36 -0
- package/dist/cjs/presets/all.codegen.js +2 -1
- package/dist/cjs/rules/consistent-css-prop-usage/index.js +19 -2
- package/dist/cjs/rules/ensure-design-token-usage/index.js +199 -227
- package/dist/cjs/rules/index.codegen.js +3 -1
- package/dist/cjs/rules/no-custom-icons/checks/has-prop.js +12 -0
- package/dist/cjs/rules/no-custom-icons/checks/is-from-import-source.js +42 -0
- package/dist/cjs/rules/no-custom-icons/checks/is-imported-jsx-element.js +10 -0
- package/dist/cjs/rules/no-custom-icons/index.js +67 -0
- package/dist/cjs/rules/no-legacy-icons/index.js +11 -83
- package/dist/cjs/rules/use-tokens-typography/index.js +4 -8
- package/dist/cjs/rules/utils/error-boundary.js +58 -11
- package/dist/es2019/presets/all.codegen.js +2 -1
- package/dist/es2019/rules/consistent-css-prop-usage/index.js +19 -2
- package/dist/es2019/rules/ensure-design-token-usage/index.js +16 -30
- package/dist/es2019/rules/index.codegen.js +3 -1
- package/dist/es2019/rules/no-custom-icons/checks/has-prop.js +4 -0
- package/dist/es2019/rules/no-custom-icons/checks/is-from-import-source.js +23 -0
- package/dist/es2019/rules/no-custom-icons/checks/is-imported-jsx-element.js +4 -0
- package/dist/es2019/rules/no-custom-icons/index.js +61 -0
- package/dist/es2019/rules/no-legacy-icons/index.js +11 -65
- package/dist/es2019/rules/use-tokens-typography/index.js +3 -7
- package/dist/es2019/rules/utils/error-boundary.js +55 -11
- package/dist/esm/presets/all.codegen.js +2 -1
- package/dist/esm/rules/consistent-css-prop-usage/index.js +19 -2
- package/dist/esm/rules/ensure-design-token-usage/index.js +199 -227
- package/dist/esm/rules/index.codegen.js +3 -1
- package/dist/esm/rules/no-custom-icons/checks/has-prop.js +6 -0
- package/dist/esm/rules/no-custom-icons/checks/is-from-import-source.js +36 -0
- package/dist/esm/rules/no-custom-icons/checks/is-imported-jsx-element.js +4 -0
- package/dist/esm/rules/no-custom-icons/index.js +61 -0
- package/dist/esm/rules/no-legacy-icons/index.js +11 -83
- package/dist/esm/rules/use-tokens-typography/index.js +4 -8
- package/dist/esm/rules/utils/error-boundary.js +56 -10
- package/dist/types/index.codegen.d.ts +1 -0
- package/dist/types/presets/all.codegen.d.ts +2 -1
- package/dist/types/rules/consistent-css-prop-usage/types.d.ts +1 -0
- package/dist/types/rules/index.codegen.d.ts +1 -0
- package/dist/types/rules/no-custom-icons/checks/has-prop.d.ts +2 -0
- package/dist/types/rules/no-custom-icons/checks/is-from-import-source.d.ts +8 -0
- package/dist/types/rules/no-custom-icons/checks/is-imported-jsx-element.d.ts +8 -0
- package/dist/types/rules/no-custom-icons/index.d.ts +3 -0
- package/dist/types/rules/no-legacy-icons/index.d.ts +1 -2
- package/dist/types/rules/utils/error-boundary.d.ts +8 -5
- package/dist/types-ts4.5/index.codegen.d.ts +1 -0
- package/dist/types-ts4.5/presets/all.codegen.d.ts +2 -1
- package/dist/types-ts4.5/rules/consistent-css-prop-usage/types.d.ts +1 -0
- package/dist/types-ts4.5/rules/index.codegen.d.ts +1 -0
- package/dist/types-ts4.5/rules/no-custom-icons/checks/has-prop.d.ts +2 -0
- package/dist/types-ts4.5/rules/no-custom-icons/checks/is-from-import-source.d.ts +8 -0
- package/dist/types-ts4.5/rules/no-custom-icons/checks/is-imported-jsx-element.d.ts +8 -0
- package/dist/types-ts4.5/rules/no-custom-icons/index.d.ts +3 -0
- package/dist/types-ts4.5/rules/no-legacy-icons/index.d.ts +1 -2
- package/dist/types-ts4.5/rules/utils/error-boundary.d.ts +8 -5
- package/package.json +1 -1
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
var _createRule = require("../utils/create-rule");
|
|
8
|
+
var _errorBoundary = require("../utils/error-boundary");
|
|
9
|
+
var _hasProp = require("./checks/has-prop");
|
|
10
|
+
var _isFromImportSource = require("./checks/is-from-import-source");
|
|
11
|
+
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
12
|
+
|
|
13
|
+
var rule = (0, _createRule.createLintRule)({
|
|
14
|
+
meta: {
|
|
15
|
+
name: 'no-custom-icons',
|
|
16
|
+
type: 'problem',
|
|
17
|
+
docs: {
|
|
18
|
+
description: 'Enforces custom glyph icons are used.',
|
|
19
|
+
recommended: false,
|
|
20
|
+
severity: 'warn'
|
|
21
|
+
},
|
|
22
|
+
schema: [{
|
|
23
|
+
type: 'object',
|
|
24
|
+
properties: {
|
|
25
|
+
centralLocation: {
|
|
26
|
+
type: 'string'
|
|
27
|
+
},
|
|
28
|
+
failSilently: {
|
|
29
|
+
type: 'boolean'
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
additionalProperties: false
|
|
33
|
+
}],
|
|
34
|
+
messages: {
|
|
35
|
+
noCustomIcons: "Custom icons from {{importSource}} are no longer supported. Migrate to an icon from '@atlaskit/(icon-labs|icon/core|icon/utility)'{{locationMessage}}.\n[Migration guide](https://hello.atlassian.net/wiki/spaces/DST/pages/3748692796/New+ADS+iconography+-+Code+migration+guide)."
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
create: function create(context) {
|
|
39
|
+
var _context$options$;
|
|
40
|
+
var isIconBase = (0, _isFromImportSource.createIsFromImportSourceFor)('@atlaskit/icon', '@atlaskit/icon/base');
|
|
41
|
+
var _ref = (_context$options$ = context.options[0]) !== null && _context$options$ !== void 0 ? _context$options$ : {},
|
|
42
|
+
_ref$centralLocation = _ref.centralLocation,
|
|
43
|
+
centralLocation = _ref$centralLocation === void 0 ? '' : _ref$centralLocation,
|
|
44
|
+
_ref$failSilently = _ref.failSilently,
|
|
45
|
+
failSilently = _ref$failSilently === void 0 ? false : _ref$failSilently;
|
|
46
|
+
var locationMessage = centralLocation ? " or move the icon to '".concat(centralLocation, "'") : '';
|
|
47
|
+
return (0, _errorBoundary.errorBoundary)({
|
|
48
|
+
JSXElement: function JSXElement(node) {
|
|
49
|
+
var _isIconBase$getImport;
|
|
50
|
+
if (!isIconBase(node) || !(0, _hasProp.hasProp)(node, 'glyph')) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
var importSource = (_isIconBase$getImport = isIconBase.getImportSource(node)) !== null && _isIconBase$getImport !== void 0 ? _isIconBase$getImport : '';
|
|
54
|
+
context.report({
|
|
55
|
+
node: node.openingElement,
|
|
56
|
+
messageId: 'noCustomIcons',
|
|
57
|
+
data: {
|
|
58
|
+
importSource: importSource,
|
|
59
|
+
locationMessage: locationMessage
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
},
|
|
63
|
+
ImportDeclaration: isIconBase.importDeclarationHook
|
|
64
|
+
}, failSilently);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
var _default = exports.default = rule;
|
|
@@ -60,95 +60,23 @@ var rule = (0, _createRule.createLintRule)({
|
|
|
60
60
|
checkJSXElement = _createChecks.checkJSXElement,
|
|
61
61
|
checkCallExpression = _createChecks.checkCallExpression,
|
|
62
62
|
throwErrors = _createChecks.throwErrors;
|
|
63
|
-
return {
|
|
63
|
+
return (0, _errorBoundary.errorBoundary)({
|
|
64
64
|
// Track imports of relevant components
|
|
65
|
-
ImportDeclaration:
|
|
66
|
-
(0, _errorBoundary.errorBoundary)(function () {
|
|
67
|
-
return checkImportDeclarations(node);
|
|
68
|
-
}, {
|
|
69
|
-
config: {
|
|
70
|
-
failSilently: failSilently
|
|
71
|
-
}
|
|
72
|
-
});
|
|
73
|
-
},
|
|
65
|
+
ImportDeclaration: checkImportDeclarations,
|
|
74
66
|
// Keep track of the relevant variable declarations and renames
|
|
75
|
-
VariableDeclaration:
|
|
76
|
-
(0, _errorBoundary.errorBoundary)(function () {
|
|
77
|
-
return checkVariableDeclarations(node);
|
|
78
|
-
}, {
|
|
79
|
-
config: {
|
|
80
|
-
failSilently: failSilently
|
|
81
|
-
}
|
|
82
|
-
});
|
|
83
|
-
},
|
|
67
|
+
VariableDeclaration: checkVariableDeclarations,
|
|
84
68
|
// Case: default re-exports. Can't be auto-migrated
|
|
85
|
-
ExportDefaultDeclaration:
|
|
86
|
-
|
|
87
|
-
return checkExportDefaultDeclaration(node);
|
|
88
|
-
}, {
|
|
89
|
-
config: {
|
|
90
|
-
failSilently: failSilently
|
|
91
|
-
}
|
|
92
|
-
});
|
|
93
|
-
},
|
|
94
|
-
ExportNamedDeclaration: function ExportNamedDeclaration(node) {
|
|
95
|
-
(0, _errorBoundary.errorBoundary)(function () {
|
|
96
|
-
return checkExportNamedVariables(node);
|
|
97
|
-
}, {
|
|
98
|
-
config: {
|
|
99
|
-
failSilently: failSilently
|
|
100
|
-
}
|
|
101
|
-
});
|
|
102
|
-
},
|
|
69
|
+
ExportDefaultDeclaration: checkExportDefaultDeclaration,
|
|
70
|
+
ExportNamedDeclaration: checkExportNamedVariables,
|
|
103
71
|
// Legacy icons found in arrays/objects
|
|
104
|
-
'ObjectExpression > Property > Identifier, ArrayExpression > Identifier ':
|
|
105
|
-
(0, _errorBoundary.errorBoundary)(function () {
|
|
106
|
-
return checkArrayOrMap(node);
|
|
107
|
-
}, {
|
|
108
|
-
config: {
|
|
109
|
-
failSilently: failSilently
|
|
110
|
-
}
|
|
111
|
-
});
|
|
112
|
-
},
|
|
72
|
+
'ObjectExpression > Property > Identifier, ArrayExpression > Identifier ': checkArrayOrMap,
|
|
113
73
|
// Legacy icons passed in via props, as JSX identifier (i.e. icon={AddIcon})
|
|
114
|
-
'JSXOpeningElement > JSXAttribute > JSXExpressionContainer > Identifier':
|
|
115
|
-
|
|
116
|
-
return checkIconAsProp(node);
|
|
117
|
-
}, {
|
|
118
|
-
config: {
|
|
119
|
-
failSilently: failSilently
|
|
120
|
-
}
|
|
121
|
-
});
|
|
122
|
-
},
|
|
123
|
-
JSXElement: function JSXElement(node) {
|
|
124
|
-
(0, _errorBoundary.errorBoundary)(function () {
|
|
125
|
-
return checkJSXElement(node);
|
|
126
|
-
}, {
|
|
127
|
-
config: {
|
|
128
|
-
failSilently: failSilently
|
|
129
|
-
}
|
|
130
|
-
});
|
|
131
|
-
},
|
|
74
|
+
'JSXOpeningElement > JSXAttribute > JSXExpressionContainer > Identifier': checkIconAsProp,
|
|
75
|
+
JSXElement: checkJSXElement,
|
|
132
76
|
// Icons called as an argument of a function (i.e. icon={DefaultIcon(AddIcon)})
|
|
133
|
-
CallExpression:
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
}, {
|
|
137
|
-
config: {
|
|
138
|
-
failSilently: failSilently
|
|
139
|
-
}
|
|
140
|
-
});
|
|
141
|
-
},
|
|
142
|
-
'Program:exit': function ProgramExit() {
|
|
143
|
-
(0, _errorBoundary.errorBoundary)(function () {
|
|
144
|
-
return throwErrors();
|
|
145
|
-
}, {
|
|
146
|
-
config: {
|
|
147
|
-
failSilently: failSilently
|
|
148
|
-
}
|
|
149
|
-
});
|
|
150
|
-
}
|
|
151
|
-
};
|
|
77
|
+
CallExpression: checkCallExpression,
|
|
78
|
+
'Program:exit': throwErrors
|
|
79
|
+
}, failSilently);
|
|
152
80
|
}
|
|
153
81
|
});
|
|
154
82
|
var _default = exports.default = rule;
|
|
@@ -12,16 +12,12 @@ var create = function create(context) {
|
|
|
12
12
|
var config = (0, _config.getConfig)(context.options[0]);
|
|
13
13
|
return {
|
|
14
14
|
// const styles = css({ fontSize: '14px, ... }), styled.div({ fontSize: 14, ... })
|
|
15
|
-
ObjectExpression: function
|
|
16
|
-
return (
|
|
17
|
-
|
|
18
|
-
context: context,
|
|
19
|
-
config: config
|
|
20
|
-
});
|
|
21
|
-
}, {
|
|
15
|
+
ObjectExpression: (0, _errorBoundary.errorBoundary)(function (node) {
|
|
16
|
+
return _styleObject.StyleObject.lint(node, {
|
|
17
|
+
context: context,
|
|
22
18
|
config: config
|
|
23
19
|
});
|
|
24
|
-
}
|
|
20
|
+
}, config)
|
|
25
21
|
};
|
|
26
22
|
};
|
|
27
23
|
var rule = (0, _createRule.createLintRule)({
|
|
@@ -1,9 +1,18 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
3
4
|
Object.defineProperty(exports, "__esModule", {
|
|
4
5
|
value: true
|
|
5
6
|
});
|
|
6
|
-
exports.errorBoundary =
|
|
7
|
+
exports.errorBoundary = errorBoundary;
|
|
8
|
+
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
9
|
+
var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof"));
|
|
10
|
+
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
11
|
+
|
|
12
|
+
// Need to intersect type RuleListener with a generic function to allow use of Parameters<...> to be used
|
|
13
|
+
|
|
14
|
+
// Allow config to be to be easily passed from rules
|
|
15
|
+
|
|
7
16
|
/**
|
|
8
17
|
* ESLint rules should NEVER throw exceptions, because that breaks the VSCode ESLint server
|
|
9
18
|
* (and probably the IntelliJ one too), which causes linting to fail in a file.
|
|
@@ -11,14 +20,52 @@ exports.errorBoundary = void 0;
|
|
|
11
20
|
* It also breaks CI, which was the reason this error boundary was added. It's a final
|
|
12
21
|
* catch all.
|
|
13
22
|
*/
|
|
14
|
-
|
|
15
|
-
var config =
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
+
function errorBoundary(ruleOrRules) {
|
|
24
|
+
var config = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
|
|
25
|
+
var failSilently = failSilentlyFromConfig(config);
|
|
26
|
+
if (isSingleRuleListener(ruleOrRules)) {
|
|
27
|
+
return wrapSingleRuleListener(ruleOrRules, failSilently);
|
|
28
|
+
}
|
|
29
|
+
return wrapRuleListener(ruleOrRules, failSilently);
|
|
30
|
+
}
|
|
31
|
+
function isSingleRuleListener(rule) {
|
|
32
|
+
return typeof rule === 'function';
|
|
33
|
+
}
|
|
34
|
+
function failSilentlyFromConfig(c) {
|
|
35
|
+
switch ((0, _typeof2.default)(c)) {
|
|
36
|
+
case 'undefined':
|
|
37
|
+
return false;
|
|
38
|
+
case 'boolean':
|
|
39
|
+
return c;
|
|
40
|
+
case 'object':
|
|
41
|
+
if ('failSilently' in c) {
|
|
42
|
+
var _c$failSilently;
|
|
43
|
+
return (_c$failSilently = c.failSilently) !== null && _c$failSilently !== void 0 ? _c$failSilently : false;
|
|
44
|
+
} else if ('config' in c) {
|
|
45
|
+
var _c$config$failSilentl;
|
|
46
|
+
return (_c$config$failSilentl = c.config.failSilently) !== null && _c$config$failSilentl !== void 0 ? _c$config$failSilentl : false;
|
|
47
|
+
}
|
|
48
|
+
return false;
|
|
49
|
+
default:
|
|
50
|
+
throw new Error('Invalid config');
|
|
23
51
|
}
|
|
24
|
-
}
|
|
52
|
+
}
|
|
53
|
+
function wrapSingleRuleListener(rule, failSilently) {
|
|
54
|
+
return function () {
|
|
55
|
+
try {
|
|
56
|
+
rule.apply(void 0, arguments);
|
|
57
|
+
} catch (err) {
|
|
58
|
+
if (!failSilently) {
|
|
59
|
+
// eslint-disable-next-line no-console
|
|
60
|
+
console.warn(err);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
function wrapRuleListener(ruleListener, failSilently) {
|
|
66
|
+
return Object.entries(ruleListener).reduce(function (wrappedRuleListener, e) {
|
|
67
|
+
var ruleName = e[0];
|
|
68
|
+
var rule = e[1];
|
|
69
|
+
return Object.assign(wrappedRuleListener, (0, _defineProperty2.default)({}, ruleName, wrapSingleRuleListener(rule, failSilently)));
|
|
70
|
+
}, {});
|
|
71
|
+
}
|
|
@@ -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::ab43b6e1a867d07b9a27eae78d48834a>>
|
|
4
4
|
* @codegenCommand yarn workspace @atlaskit/eslint-plugin-design-system codegen
|
|
5
5
|
*/
|
|
6
6
|
export default {
|
|
@@ -12,6 +12,7 @@ export default {
|
|
|
12
12
|
'@atlaskit/design-system/icon-label': 'warn',
|
|
13
13
|
'@atlaskit/design-system/no-banned-imports': 'error',
|
|
14
14
|
'@atlaskit/design-system/no-css-tagged-template-expression': 'error',
|
|
15
|
+
'@atlaskit/design-system/no-custom-icons': 'warn',
|
|
15
16
|
'@atlaskit/design-system/no-deprecated-apis': 'error',
|
|
16
17
|
'@atlaskit/design-system/no-deprecated-design-token-usage': 'warn',
|
|
17
18
|
'@atlaskit/design-system/no-deprecated-imports': 'error',
|
|
@@ -449,7 +449,8 @@ const defaultConfig = {
|
|
|
449
449
|
cssImportSource: CSS_IN_JS_IMPORTS.compiled,
|
|
450
450
|
xcssImportSource: CSS_IN_JS_IMPORTS.atlaskitPrimitives,
|
|
451
451
|
excludeReactComponents: false,
|
|
452
|
-
autoFix: true
|
|
452
|
+
autoFix: true,
|
|
453
|
+
shouldAlwaysCheckXcss: false
|
|
453
454
|
};
|
|
454
455
|
const rule = createLintRule({
|
|
455
456
|
meta: {
|
|
@@ -492,6 +493,9 @@ const rule = createLintRule({
|
|
|
492
493
|
excludeReactComponents: {
|
|
493
494
|
type: 'boolean'
|
|
494
495
|
},
|
|
496
|
+
shouldAlwaysCheckXcss: {
|
|
497
|
+
type: 'boolean'
|
|
498
|
+
},
|
|
495
499
|
autoFix: {
|
|
496
500
|
type: 'boolean'
|
|
497
501
|
}
|
|
@@ -508,7 +512,20 @@ const rule = createLintRule({
|
|
|
508
512
|
name,
|
|
509
513
|
value
|
|
510
514
|
} = node;
|
|
511
|
-
|
|
515
|
+
|
|
516
|
+
/**
|
|
517
|
+
* We skip linting `xcss` attributes if:
|
|
518
|
+
*
|
|
519
|
+
* - excludeReactComponents === true
|
|
520
|
+
* - shouldAlwaysCheckXcss === false
|
|
521
|
+
*
|
|
522
|
+
* In the future we may want to remove `shouldAlwaysCheckXcss`
|
|
523
|
+
* and just always lint `xcss`, regardless of `excludeReactComponents`
|
|
524
|
+
*/
|
|
525
|
+
if (mergedConfig.excludeReactComponents && name.name === 'xcss' && !mergedConfig.shouldAlwaysCheckXcss) {
|
|
526
|
+
return;
|
|
527
|
+
}
|
|
528
|
+
if (mergedConfig.excludeReactComponents && node.parent.type === 'JSXOpeningElement' && name.name === 'css') {
|
|
512
529
|
// e.g. <item.before />
|
|
513
530
|
if (node.parent.name.type === 'JSXMemberExpression') {
|
|
514
531
|
return;
|
|
@@ -27,25 +27,21 @@ const createWithConfig = initialConfig => context => {
|
|
|
27
27
|
failSilently: (userConfig === null || userConfig === void 0 ? void 0 : userConfig.failSilently) || defaultConfig.failSilently
|
|
28
28
|
};
|
|
29
29
|
let tokenNode = null;
|
|
30
|
-
return {
|
|
31
|
-
ImportDeclaration: node =>
|
|
30
|
+
return errorBoundary({
|
|
31
|
+
ImportDeclaration: node => {
|
|
32
32
|
if (node.source.value === '@atlaskit/tokens' && config.applyImport) {
|
|
33
33
|
tokenNode = node;
|
|
34
34
|
}
|
|
35
|
-
},
|
|
36
|
-
config
|
|
37
|
-
}),
|
|
35
|
+
},
|
|
38
36
|
// For expressions within template literals (e.g. `color: ${red}`) - color only
|
|
39
|
-
'TemplateLiteral > Identifier': node =>
|
|
37
|
+
'TemplateLiteral > Identifier': node => {
|
|
40
38
|
if (config.domains.includes('color')) {
|
|
41
39
|
return lintTemplateIdentifierForColor(node, context, config);
|
|
42
40
|
}
|
|
43
41
|
return;
|
|
44
|
-
},
|
|
45
|
-
config
|
|
46
|
-
}),
|
|
42
|
+
},
|
|
47
43
|
// const styles = css({ color: 'red', margin: '4px' }), styled.div({ color: 'red', margin: '4px' })
|
|
48
|
-
ObjectExpression: parentNode =>
|
|
44
|
+
ObjectExpression: parentNode => {
|
|
49
45
|
const {
|
|
50
46
|
references
|
|
51
47
|
} = context.getScope();
|
|
@@ -115,13 +111,11 @@ const createWithConfig = initialConfig => context => {
|
|
|
115
111
|
}
|
|
116
112
|
}
|
|
117
113
|
parentNode.properties.forEach(findObjectStyles);
|
|
118
|
-
},
|
|
119
|
-
config
|
|
120
|
-
}),
|
|
114
|
+
},
|
|
121
115
|
// CSSTemplateLiteral and StyledTemplateLiteral
|
|
122
116
|
// const cssTemplateLiteral = css`color: red; padding: 12px`;
|
|
123
117
|
// const styledTemplateLiteral = styled.p`color: red; padding: 8px`;
|
|
124
|
-
'TaggedTemplateExpression[tag.name="css"],TaggedTemplateExpression[tag.object.name="styled"],TaggedTemplateExpression[tag.callee.name="styled"]': node =>
|
|
118
|
+
'TaggedTemplateExpression[tag.name="css"],TaggedTemplateExpression[tag.object.name="styled"],TaggedTemplateExpression[tag.callee.name="styled"]': node => {
|
|
125
119
|
// To force the correct node type
|
|
126
120
|
if (!isNodeOfType(node, 'TaggedTemplateExpression')) {
|
|
127
121
|
return;
|
|
@@ -249,37 +243,29 @@ const createWithConfig = initialConfig => context => {
|
|
|
249
243
|
}
|
|
250
244
|
});
|
|
251
245
|
}
|
|
252
|
-
},
|
|
253
|
-
config
|
|
254
|
-
}),
|
|
246
|
+
},
|
|
255
247
|
// For inline JSX styles - literals (e.g. <Test color="red"/>) - color only
|
|
256
|
-
'JSXAttribute > Literal': node =>
|
|
248
|
+
'JSXAttribute > Literal': node => {
|
|
257
249
|
if (config.domains.includes('color')) {
|
|
258
250
|
return lintJSXLiteralForColor(node, context, config);
|
|
259
251
|
}
|
|
260
252
|
return;
|
|
261
|
-
},
|
|
262
|
-
config
|
|
263
|
-
}),
|
|
253
|
+
},
|
|
264
254
|
// For inline JSX styles - members (e.g. <Test color={color.red}/>) - color only
|
|
265
|
-
'JSXExpressionContainer > MemberExpression': node =>
|
|
255
|
+
'JSXExpressionContainer > MemberExpression': node => {
|
|
266
256
|
if (config.domains.includes('color')) {
|
|
267
257
|
return lintJSXMemberForColor(node, context, config);
|
|
268
258
|
}
|
|
269
259
|
return;
|
|
270
|
-
},
|
|
271
|
-
config
|
|
272
|
-
}),
|
|
260
|
+
},
|
|
273
261
|
// For inline JSX styles - identifiers (e.g. <Test color={red}/>) - color only
|
|
274
|
-
'JSXExpressionContainer > Identifier': node =>
|
|
262
|
+
'JSXExpressionContainer > Identifier': node => {
|
|
275
263
|
if (config.domains.includes('color')) {
|
|
276
264
|
return lintJSXIdentifierForColor(node, context, config);
|
|
277
265
|
}
|
|
278
266
|
return;
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
})
|
|
282
|
-
};
|
|
267
|
+
}
|
|
268
|
+
}, config);
|
|
283
269
|
};
|
|
284
270
|
const rule = createLintRule({
|
|
285
271
|
meta: ruleMeta,
|
|
@@ -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::402e6eb5433560b1032e5ed926bb5564>>
|
|
4
4
|
* @codegenCommand yarn workspace @atlaskit/eslint-plugin-design-system codegen
|
|
5
5
|
*/
|
|
6
6
|
import consistentCssPropUsage from './consistent-css-prop-usage';
|
|
@@ -9,6 +9,7 @@ import ensureDesignTokenUsagePreview from './ensure-design-token-usage-preview';
|
|
|
9
9
|
import iconLabel from './icon-label';
|
|
10
10
|
import noBannedImports from './no-banned-imports';
|
|
11
11
|
import noCssTaggedTemplateExpression from './no-css-tagged-template-expression';
|
|
12
|
+
import noCustomIcons from './no-custom-icons';
|
|
12
13
|
import noDeprecatedApis from './no-deprecated-apis';
|
|
13
14
|
import noDeprecatedDesignTokenUsage from './no-deprecated-design-token-usage';
|
|
14
15
|
import noDeprecatedImports from './no-deprecated-imports';
|
|
@@ -50,6 +51,7 @@ export default {
|
|
|
50
51
|
'icon-label': iconLabel,
|
|
51
52
|
'no-banned-imports': noBannedImports,
|
|
52
53
|
'no-css-tagged-template-expression': noCssTaggedTemplateExpression,
|
|
54
|
+
'no-custom-icons': noCustomIcons,
|
|
53
55
|
'no-deprecated-apis': noDeprecatedApis,
|
|
54
56
|
'no-deprecated-design-token-usage': noDeprecatedDesignTokenUsage,
|
|
55
57
|
'no-deprecated-imports': noDeprecatedImports,
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { isImportedJSXElement } from './is-imported-jsx-element';
|
|
2
|
+
export function createIsFromImportSourceFor(...importSources) {
|
|
3
|
+
const literalImportSources = importSources.filter(s => typeof s === 'string');
|
|
4
|
+
const matchImportSources = importSources.filter(s => s instanceof RegExp);
|
|
5
|
+
const varImportSourceMap = new Map();
|
|
6
|
+
function isFromImportSource(node) {
|
|
7
|
+
return isImportedJSXElement(node) && varImportSourceMap.has(node.openingElement.name.name);
|
|
8
|
+
}
|
|
9
|
+
isFromImportSource.importDeclarationHook = node => {
|
|
10
|
+
const source = node.source.value;
|
|
11
|
+
if (typeof source !== 'string' || !(literalImportSources.includes(source) || matchImportSources.some(r => r.test(source)))) {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
node.specifiers.filter(spec => ['ImportSpecifier', 'ImportDefaultSpecifier'].includes(spec.type)).forEach(spec => varImportSourceMap.set(spec.local.name, source));
|
|
15
|
+
};
|
|
16
|
+
isFromImportSource.getImportSource = node => {
|
|
17
|
+
if (!isFromImportSource(node)) {
|
|
18
|
+
throw new Error('Node is not an imported JSX element');
|
|
19
|
+
}
|
|
20
|
+
return varImportSourceMap.get(node.openingElement.name.name);
|
|
21
|
+
};
|
|
22
|
+
return isFromImportSource;
|
|
23
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
2
|
+
|
|
3
|
+
import { createLintRule } from '../utils/create-rule';
|
|
4
|
+
import { errorBoundary } from '../utils/error-boundary';
|
|
5
|
+
import { hasProp } from './checks/has-prop';
|
|
6
|
+
import { createIsFromImportSourceFor } from './checks/is-from-import-source';
|
|
7
|
+
const rule = createLintRule({
|
|
8
|
+
meta: {
|
|
9
|
+
name: 'no-custom-icons',
|
|
10
|
+
type: 'problem',
|
|
11
|
+
docs: {
|
|
12
|
+
description: 'Enforces custom glyph icons are used.',
|
|
13
|
+
recommended: false,
|
|
14
|
+
severity: 'warn'
|
|
15
|
+
},
|
|
16
|
+
schema: [{
|
|
17
|
+
type: 'object',
|
|
18
|
+
properties: {
|
|
19
|
+
centralLocation: {
|
|
20
|
+
type: 'string'
|
|
21
|
+
},
|
|
22
|
+
failSilently: {
|
|
23
|
+
type: 'boolean'
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
additionalProperties: false
|
|
27
|
+
}],
|
|
28
|
+
messages: {
|
|
29
|
+
noCustomIcons: `Custom icons from {{importSource}} are no longer supported. Migrate to an icon from '@atlaskit/(icon-labs|icon/core|icon/utility)'{{locationMessage}}.
|
|
30
|
+
[Migration guide](https://hello.atlassian.net/wiki/spaces/DST/pages/3748692796/New+ADS+iconography+-+Code+migration+guide).`
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
create(context) {
|
|
34
|
+
var _context$options$;
|
|
35
|
+
const isIconBase = createIsFromImportSourceFor('@atlaskit/icon', '@atlaskit/icon/base');
|
|
36
|
+
const {
|
|
37
|
+
centralLocation = '',
|
|
38
|
+
failSilently = false
|
|
39
|
+
} = (_context$options$ = context.options[0]) !== null && _context$options$ !== void 0 ? _context$options$ : {};
|
|
40
|
+
const locationMessage = centralLocation ? ` or move the icon to '${centralLocation}'` : '';
|
|
41
|
+
return errorBoundary({
|
|
42
|
+
JSXElement(node) {
|
|
43
|
+
var _isIconBase$getImport;
|
|
44
|
+
if (!isIconBase(node) || !hasProp(node, 'glyph')) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
const importSource = (_isIconBase$getImport = isIconBase.getImportSource(node)) !== null && _isIconBase$getImport !== void 0 ? _isIconBase$getImport : '';
|
|
48
|
+
context.report({
|
|
49
|
+
node: node.openingElement,
|
|
50
|
+
messageId: 'noCustomIcons',
|
|
51
|
+
data: {
|
|
52
|
+
importSource,
|
|
53
|
+
locationMessage
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
},
|
|
57
|
+
ImportDeclaration: isIconBase.importDeclarationHook
|
|
58
|
+
}, failSilently);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
export default rule;
|
|
@@ -56,77 +56,23 @@ const rule = createLintRule({
|
|
|
56
56
|
checkCallExpression,
|
|
57
57
|
throwErrors
|
|
58
58
|
} = createChecks(context);
|
|
59
|
-
return {
|
|
59
|
+
return errorBoundary({
|
|
60
60
|
// Track imports of relevant components
|
|
61
|
-
ImportDeclaration
|
|
62
|
-
errorBoundary(() => checkImportDeclarations(node), {
|
|
63
|
-
config: {
|
|
64
|
-
failSilently
|
|
65
|
-
}
|
|
66
|
-
});
|
|
67
|
-
},
|
|
61
|
+
ImportDeclaration: checkImportDeclarations,
|
|
68
62
|
// Keep track of the relevant variable declarations and renames
|
|
69
|
-
VariableDeclaration
|
|
70
|
-
errorBoundary(() => checkVariableDeclarations(node), {
|
|
71
|
-
config: {
|
|
72
|
-
failSilently
|
|
73
|
-
}
|
|
74
|
-
});
|
|
75
|
-
},
|
|
63
|
+
VariableDeclaration: checkVariableDeclarations,
|
|
76
64
|
// Case: default re-exports. Can't be auto-migrated
|
|
77
|
-
ExportDefaultDeclaration
|
|
78
|
-
|
|
79
|
-
config: {
|
|
80
|
-
failSilently
|
|
81
|
-
}
|
|
82
|
-
});
|
|
83
|
-
},
|
|
84
|
-
ExportNamedDeclaration(node) {
|
|
85
|
-
errorBoundary(() => checkExportNamedVariables(node), {
|
|
86
|
-
config: {
|
|
87
|
-
failSilently
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
|
-
},
|
|
65
|
+
ExportDefaultDeclaration: checkExportDefaultDeclaration,
|
|
66
|
+
ExportNamedDeclaration: checkExportNamedVariables,
|
|
91
67
|
// Legacy icons found in arrays/objects
|
|
92
|
-
'ObjectExpression > Property > Identifier, ArrayExpression > Identifier ':
|
|
93
|
-
errorBoundary(() => checkArrayOrMap(node), {
|
|
94
|
-
config: {
|
|
95
|
-
failSilently
|
|
96
|
-
}
|
|
97
|
-
});
|
|
98
|
-
},
|
|
68
|
+
'ObjectExpression > Property > Identifier, ArrayExpression > Identifier ': checkArrayOrMap,
|
|
99
69
|
// Legacy icons passed in via props, as JSX identifier (i.e. icon={AddIcon})
|
|
100
|
-
'JSXOpeningElement > JSXAttribute > JSXExpressionContainer > Identifier':
|
|
101
|
-
|
|
102
|
-
config: {
|
|
103
|
-
failSilently
|
|
104
|
-
}
|
|
105
|
-
});
|
|
106
|
-
},
|
|
107
|
-
JSXElement(node) {
|
|
108
|
-
errorBoundary(() => checkJSXElement(node), {
|
|
109
|
-
config: {
|
|
110
|
-
failSilently
|
|
111
|
-
}
|
|
112
|
-
});
|
|
113
|
-
},
|
|
70
|
+
'JSXOpeningElement > JSXAttribute > JSXExpressionContainer > Identifier': checkIconAsProp,
|
|
71
|
+
JSXElement: checkJSXElement,
|
|
114
72
|
// Icons called as an argument of a function (i.e. icon={DefaultIcon(AddIcon)})
|
|
115
|
-
CallExpression:
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
failSilently
|
|
119
|
-
}
|
|
120
|
-
});
|
|
121
|
-
},
|
|
122
|
-
'Program:exit': () => {
|
|
123
|
-
errorBoundary(() => throwErrors(), {
|
|
124
|
-
config: {
|
|
125
|
-
failSilently
|
|
126
|
-
}
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
|
-
};
|
|
73
|
+
CallExpression: checkCallExpression,
|
|
74
|
+
'Program:exit': throwErrors
|
|
75
|
+
}, failSilently);
|
|
130
76
|
}
|
|
131
77
|
});
|
|
132
78
|
export default rule;
|
|
@@ -6,14 +6,10 @@ const create = context => {
|
|
|
6
6
|
const config = getConfig(context.options[0]);
|
|
7
7
|
return {
|
|
8
8
|
// const styles = css({ fontSize: '14px, ... }), styled.div({ fontSize: 14, ... })
|
|
9
|
-
ObjectExpression: node =>
|
|
10
|
-
|
|
11
|
-
context,
|
|
12
|
-
config
|
|
13
|
-
});
|
|
14
|
-
}, {
|
|
9
|
+
ObjectExpression: errorBoundary(node => StyleObject.lint(node, {
|
|
10
|
+
context,
|
|
15
11
|
config
|
|
16
|
-
})
|
|
12
|
+
}), config)
|
|
17
13
|
};
|
|
18
14
|
};
|
|
19
15
|
const rule = createLintRule({
|