@atlaskit/eslint-plugin-design-system 4.0.0 → 4.2.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 +31 -0
- package/dist/cjs/index.js +14 -3
- package/dist/cjs/rules/ensure-design-token-usage/index.js +3 -0
- package/dist/cjs/rules/no-deprecated-apis/index.js +91 -0
- package/dist/cjs/rules/no-deprecated-design-token-usage/index.js +76 -0
- package/dist/cjs/rules/no-deprecated-imports/index.js +45 -33
- package/dist/cjs/rules/no-deprecated-imports/paths.js +43 -15
- package/dist/cjs/rules/no-unsafe-design-token-usage/index.js +19 -5
- package/dist/cjs/rules/use-visually-hidden/constants.js +12 -0
- package/dist/cjs/rules/use-visually-hidden/fix-jsx.js +39 -0
- package/dist/cjs/rules/use-visually-hidden/fix-vanilla.js +35 -0
- package/dist/cjs/rules/use-visually-hidden/index.js +194 -0
- package/dist/cjs/rules/use-visually-hidden/utils.js +91 -0
- package/dist/cjs/rules/utils/get-import-node-by-source.js +23 -0
- package/dist/cjs/rules/utils/is-color.js +3 -2
- package/dist/cjs/rules/utils/is-node.js +33 -3
- package/dist/cjs/rules/utils/remove-named-import.js +29 -0
- package/dist/cjs/version.json +1 -1
- package/dist/es2019/index.js +10 -2
- package/dist/es2019/rules/ensure-design-token-usage/index.js +3 -0
- package/dist/es2019/rules/no-deprecated-apis/index.js +72 -0
- package/dist/es2019/rules/no-deprecated-design-token-usage/index.js +58 -0
- package/dist/es2019/rules/no-deprecated-imports/index.js +45 -32
- package/dist/es2019/rules/no-deprecated-imports/paths.js +41 -14
- package/dist/es2019/rules/no-unsafe-design-token-usage/index.js +12 -5
- package/dist/es2019/rules/use-visually-hidden/constants.js +3 -0
- package/dist/es2019/rules/use-visually-hidden/fix-jsx.js +24 -0
- package/dist/es2019/rules/use-visually-hidden/fix-vanilla.js +21 -0
- package/dist/es2019/rules/use-visually-hidden/index.js +169 -0
- package/dist/es2019/rules/use-visually-hidden/utils.js +62 -0
- package/dist/es2019/rules/utils/get-import-node-by-source.js +10 -0
- package/dist/es2019/rules/utils/is-color.js +2 -1
- package/dist/es2019/rules/utils/is-node.js +19 -2
- package/dist/es2019/rules/utils/remove-named-import.js +16 -0
- package/dist/es2019/version.json +1 -1
- package/dist/esm/index.js +10 -2
- package/dist/esm/rules/ensure-design-token-usage/index.js +3 -0
- package/dist/esm/rules/no-deprecated-apis/index.js +81 -0
- package/dist/esm/rules/no-deprecated-design-token-usage/index.js +66 -0
- package/dist/esm/rules/no-deprecated-imports/index.js +45 -32
- package/dist/esm/rules/no-deprecated-imports/paths.js +41 -14
- package/dist/esm/rules/no-unsafe-design-token-usage/index.js +20 -5
- package/dist/esm/rules/use-visually-hidden/constants.js +3 -0
- package/dist/esm/rules/use-visually-hidden/fix-jsx.js +26 -0
- package/dist/esm/rules/use-visually-hidden/fix-vanilla.js +23 -0
- package/dist/esm/rules/use-visually-hidden/index.js +180 -0
- package/dist/esm/rules/use-visually-hidden/utils.js +74 -0
- package/dist/esm/rules/utils/get-import-node-by-source.js +14 -0
- package/dist/esm/rules/utils/is-color.js +2 -1
- package/dist/esm/rules/utils/is-node.js +22 -1
- package/dist/esm/rules/utils/remove-named-import.js +20 -0
- package/dist/esm/version.json +1 -1
- package/dist/types/index.d.ts +5 -0
- package/dist/types/rules/no-deprecated-apis/index.d.ts +3 -0
- package/dist/types/rules/no-deprecated-design-token-usage/index.d.ts +3 -0
- package/dist/types/rules/no-deprecated-imports/paths.d.ts +33 -14
- package/dist/types/rules/use-visually-hidden/constants.d.ts +3 -0
- package/dist/types/rules/use-visually-hidden/fix-jsx.d.ts +3 -0
- package/dist/types/rules/use-visually-hidden/fix-vanilla.d.ts +3 -0
- package/dist/types/rules/use-visually-hidden/index.d.ts +3 -0
- package/dist/types/rules/use-visually-hidden/utils.d.ts +35 -0
- package/dist/types/rules/utils/get-import-node-by-source.d.ts +8 -0
- package/dist/types/rules/utils/is-node.d.ts +7 -0
- package/dist/types/rules/utils/remove-named-import.d.ts +8 -0
- package/package.json +6 -2
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
|
|
5
|
+
Object.defineProperty(exports, "__esModule", {
|
|
6
|
+
value: true
|
|
7
|
+
});
|
|
8
|
+
exports.default = void 0;
|
|
9
|
+
|
|
10
|
+
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
|
|
11
|
+
|
|
12
|
+
var _isNode = require("../utils/is-node");
|
|
13
|
+
|
|
14
|
+
var _fixJsx = _interopRequireDefault(require("./fix-jsx"));
|
|
15
|
+
|
|
16
|
+
var _fixVanilla = _interopRequireDefault(require("./fix-vanilla"));
|
|
17
|
+
|
|
18
|
+
var _utils = require("./utils");
|
|
19
|
+
|
|
20
|
+
/* eslint-disable @atlaskit/design-system/use-visually-hidden */
|
|
21
|
+
var THEME_IMPORT_NAMES = ['visuallyHidden', 'assistive'];
|
|
22
|
+
var rule = {
|
|
23
|
+
meta: {
|
|
24
|
+
type: 'suggestion',
|
|
25
|
+
fixable: 'code',
|
|
26
|
+
docs: {
|
|
27
|
+
description: 'Suggest usage of the `@atlaskit/visually-hidden` component instead of either the `@atlaskit/theme` mixins or just something the user has rolled themselves.',
|
|
28
|
+
recommended: true
|
|
29
|
+
},
|
|
30
|
+
messages: {
|
|
31
|
+
noDeprecatedUsage: 'Using the export `{{local}}` from `{{import}}` as a mixin is discouraged. Please use `@atlaskit/visually-hidden` instead.',
|
|
32
|
+
noDeprecated: 'The export `{{local}}` from `{{import}}` is deprecated. Please use `@atlaskit/visually-hidden` instead.',
|
|
33
|
+
suggestion: 'This CSS closely matches the implementation of a visually hidden element. You should consider using the `@atlaskit/visually-hidden` component instead.'
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
create: function create(context) {
|
|
37
|
+
var source = context.getSourceCode();
|
|
38
|
+
return {
|
|
39
|
+
ImportDeclaration: function ImportDeclaration(node) {
|
|
40
|
+
var isThemeNode = node.source.value === '@atlaskit/theme' || node.source.value === '@atlaskit/theme/constants';
|
|
41
|
+
|
|
42
|
+
if (!isThemeNode) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
var visuallyHiddenOrAssistive = node.specifiers.filter(function (specifier) {
|
|
47
|
+
return specifier.type === 'ImportSpecifier';
|
|
48
|
+
}).find(function (specifier) {
|
|
49
|
+
return THEME_IMPORT_NAMES.includes(specifier.imported.name);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
if (!visuallyHiddenOrAssistive) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
context.getDeclaredVariables(visuallyHiddenOrAssistive).forEach(function (someNode) {
|
|
57
|
+
someNode.references.map(function (innerNode) {
|
|
58
|
+
return innerNode.identifier;
|
|
59
|
+
}).forEach(function (idNode) {
|
|
60
|
+
// @ts-ignore JSX is not typed correctly in eslint
|
|
61
|
+
if ((idNode === null || idNode === void 0 ? void 0 : idNode.parent.type) === 'JSXExpressionContainer') {
|
|
62
|
+
context.report({
|
|
63
|
+
node: idNode.parent,
|
|
64
|
+
messageId: 'noDeprecatedUsage',
|
|
65
|
+
data: {
|
|
66
|
+
import: "".concat(node.source.value),
|
|
67
|
+
local: visuallyHiddenOrAssistive.local.name
|
|
68
|
+
},
|
|
69
|
+
fix: (0, _fixJsx.default)(source, idNode)
|
|
70
|
+
}); // this is either a styled usage OR mixin usage in a styled usage
|
|
71
|
+
} else if (idNode.parent.type === 'CallExpression') {
|
|
72
|
+
if ((0, _isNode.isStyledObjectNode)(idNode.parent) || (0, _isNode.isStyledTemplateNode)(idNode.parent)) {
|
|
73
|
+
context.report({
|
|
74
|
+
node: idNode.parent,
|
|
75
|
+
messageId: 'noDeprecatedUsage',
|
|
76
|
+
data: {
|
|
77
|
+
import: "".concat(node.source.value),
|
|
78
|
+
local: visuallyHiddenOrAssistive.local.name
|
|
79
|
+
},
|
|
80
|
+
fix: (0, _fixVanilla.default)(source, idNode.parent)
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (idNode.parent.callee === idNode) {
|
|
85
|
+
context.report({
|
|
86
|
+
node: idNode.parent,
|
|
87
|
+
messageId: 'noDeprecatedUsage',
|
|
88
|
+
data: {
|
|
89
|
+
import: "".concat(node.source.value),
|
|
90
|
+
local: visuallyHiddenOrAssistive.local.name
|
|
91
|
+
},
|
|
92
|
+
fix: (0, _fixVanilla.default)(source, (0, _isNode.getClosestNodeOfType)(idNode.parent, 'TaggedTemplateExpression'))
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
return context.report({
|
|
99
|
+
node: visuallyHiddenOrAssistive,
|
|
100
|
+
messageId: 'noDeprecated',
|
|
101
|
+
data: {
|
|
102
|
+
import: "".concat(node.source.value),
|
|
103
|
+
local: visuallyHiddenOrAssistive.local.name
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
},
|
|
107
|
+
CallExpression: function CallExpression(node) {
|
|
108
|
+
var _node$arguments$;
|
|
109
|
+
|
|
110
|
+
if (node.type !== 'CallExpression') {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (!(node.callee.type === 'MemberExpression' || node.callee.type === 'Identifier')) {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
var isStyled = (0, _isNode.isStyledObjectNode)(node);
|
|
119
|
+
|
|
120
|
+
if (node.callee.type === 'MemberExpression' && node.callee.object.type === 'Identifier' && node.callee.object.name !== 'styled') {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (node.callee.type === 'Identifier' && node.callee.name !== 'css') {
|
|
125
|
+
return;
|
|
126
|
+
} // This is an object style (probably)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
if (node.arguments && ((_node$arguments$ = node.arguments[0]) === null || _node$arguments$ === void 0 ? void 0 : _node$arguments$.type) === 'ObjectExpression') {
|
|
130
|
+
var matchingScore = (0, _utils.getObjectLikeness)(node.arguments[0]);
|
|
131
|
+
|
|
132
|
+
if (matchingScore > 0.8) {
|
|
133
|
+
return context.report({
|
|
134
|
+
node: node.parent,
|
|
135
|
+
messageId: 'suggestion',
|
|
136
|
+
fix: isStyled ? (0, _fixVanilla.default)(source, node) : undefined
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return null;
|
|
142
|
+
},
|
|
143
|
+
ObjectExpression: function ObjectExpression(node) {
|
|
144
|
+
if (node.parent.type === 'CallExpression') {
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
var matchingScore = (0, _utils.getObjectLikeness)(node);
|
|
149
|
+
|
|
150
|
+
if (matchingScore > 0.8) {
|
|
151
|
+
return context.report({
|
|
152
|
+
node: node,
|
|
153
|
+
messageId: 'suggestion'
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
'TaggedTemplateExpression[tag.name="css"],TaggedTemplateExpression[tag.object.name="styled"]': function TaggedTemplateExpressionTagNameCssTaggedTemplateExpressionTagObjectNameStyled(node) {
|
|
158
|
+
if (node.type !== 'TaggedTemplateExpression') {
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
var templateString = node.quasi.quasis.map(function (q) {
|
|
163
|
+
return q.value.raw;
|
|
164
|
+
}).join('');
|
|
165
|
+
var styleEntries = (0, _utils.makeTemplateLiteralIntoEntries)(templateString);
|
|
166
|
+
|
|
167
|
+
if (!styleEntries) {
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
var count = (0, _utils.countMatchingKeyValues)(styleEntries.map(function (_ref) {
|
|
172
|
+
var _ref2 = (0, _slicedToArray2.default)(_ref, 2),
|
|
173
|
+
key = _ref2[0],
|
|
174
|
+
value = _ref2[1];
|
|
175
|
+
|
|
176
|
+
return {
|
|
177
|
+
key: key,
|
|
178
|
+
value: value
|
|
179
|
+
};
|
|
180
|
+
}));
|
|
181
|
+
|
|
182
|
+
if (count > 0.8) {
|
|
183
|
+
return context.report({
|
|
184
|
+
node: node,
|
|
185
|
+
messageId: 'suggestion',
|
|
186
|
+
fix: node.tag.type !== 'Identifier' ? (0, _fixVanilla.default)(source, node) : undefined
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
var _default = rule;
|
|
194
|
+
exports.default = _default;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.makeTemplateLiteralIntoEntries = exports.getObjectLikeness = exports.getFirstImport = exports.countMatchingKeyValues = void 0;
|
|
7
|
+
// eslint-disable-next-line import/no-unresolved
|
|
8
|
+
// eslint-disable-next-line @atlaskit/design-system/use-visually-hidden
|
|
9
|
+
var referenceObject = {
|
|
10
|
+
width: '1px',
|
|
11
|
+
height: '1px',
|
|
12
|
+
padding: '0',
|
|
13
|
+
position: 'absolute',
|
|
14
|
+
border: '0',
|
|
15
|
+
clip: 'rect(1px, 1px, 1px, 1px)',
|
|
16
|
+
overflow: 'hidden',
|
|
17
|
+
whiteSpace: 'nowrap'
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Returns the first import in the esprima AST.
|
|
22
|
+
*/
|
|
23
|
+
var getFirstImport = function getFirstImport(source) {
|
|
24
|
+
return source.ast.body.find(function (node) {
|
|
25
|
+
return node.type === 'ImportDeclaration';
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Takes a template literal and returns [key, value] array of the css properties
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
exports.getFirstImport = getFirstImport;
|
|
34
|
+
|
|
35
|
+
var makeTemplateLiteralIntoEntries = function makeTemplateLiteralIntoEntries(templateString) {
|
|
36
|
+
return templateString.replace(/\n/g, '').split(/;|{|}/).filter(function (el) {
|
|
37
|
+
return !el.match(/\@/);
|
|
38
|
+
}).map(function (el) {
|
|
39
|
+
return el.trim().split(':').map(function (e) {
|
|
40
|
+
return e.trim();
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Given a node, translate the node into css key-value pairs and
|
|
46
|
+
* compare the output to the reference styles required to make a
|
|
47
|
+
* visually hidden element.
|
|
48
|
+
*
|
|
49
|
+
* @returns {number} A fraction between 0-1 depending on the object's likeness.
|
|
50
|
+
*/
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
exports.makeTemplateLiteralIntoEntries = makeTemplateLiteralIntoEntries;
|
|
54
|
+
|
|
55
|
+
var getObjectLikeness = function getObjectLikeness(node) {
|
|
56
|
+
var styleEntries = node.properties.map(function (_ref) {
|
|
57
|
+
var type = _ref.type,
|
|
58
|
+
key = _ref.key,
|
|
59
|
+
value = _ref.value;
|
|
60
|
+
|
|
61
|
+
if (type === 'Property' && key.type === 'Identifier') {
|
|
62
|
+
return {
|
|
63
|
+
key: key.name,
|
|
64
|
+
value: value.type === 'Literal' && value.value
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return null;
|
|
69
|
+
}).filter(function (node) {
|
|
70
|
+
return Boolean(node);
|
|
71
|
+
});
|
|
72
|
+
return countMatchingKeyValues(styleEntries);
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
exports.getObjectLikeness = getObjectLikeness;
|
|
76
|
+
|
|
77
|
+
var countMatchingKeyValues = function countMatchingKeyValues(styleEntries) {
|
|
78
|
+
var matchingStyleEntries = styleEntries.filter(function (entry) {
|
|
79
|
+
return entry.key in referenceObject;
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
if (styleEntries.length < 5) {
|
|
83
|
+
return 0;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return matchingStyleEntries.reduce(function (acc, curr) {
|
|
87
|
+
return acc + (referenceObject[curr === null || curr === void 0 ? void 0 : curr.key] === (curr === null || curr === void 0 ? void 0 : curr.value) ? 1.5 : 0.75);
|
|
88
|
+
}, 0) / styleEntries.length;
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
exports.countMatchingKeyValues = countMatchingKeyValues;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.getImportedNodeBySource = void 0;
|
|
7
|
+
|
|
8
|
+
/* eslint-disable import/no-unresolved */
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @param {SourceCode} source The eslint source
|
|
12
|
+
* @param {string} path The path specified to find
|
|
13
|
+
* @returns {ImportDeclaration}
|
|
14
|
+
*/
|
|
15
|
+
var getImportedNodeBySource = function getImportedNodeBySource(source, path) {
|
|
16
|
+
return source.ast.body.filter(function (node) {
|
|
17
|
+
return node.type === 'ImportDeclaration';
|
|
18
|
+
}).find(function (node) {
|
|
19
|
+
return node.source.value === path;
|
|
20
|
+
});
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
exports.getImportedNodeBySource = getImportedNodeBySource;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.
|
|
6
|
+
exports.isLegacyNamedColor = exports.isLegacyColor = exports.isHardCodedColor = exports.includesHardCodedColor = void 0;
|
|
7
7
|
var namedColors = ['black', 'silver', 'gray', 'white', 'maroon', 'red', 'purple', 'fuchsia', 'green', 'lime', 'olive', 'yellow', 'navy', 'blue', 'teal', 'aqua', 'orange', 'aliceblue', 'antiquewhite', 'aquamarine', 'azure', 'beige', 'bisque', 'blanchedalmond', 'blueviolet', 'brown', 'burlywood', 'cadetblue', 'chartreuse', 'chocolate', 'coral', 'cornflowerblue', 'cornsilk', 'crimson', 'cyan', 'darkblue', 'darkcyan', 'darkgoldenrod', 'darkgray', 'darkgreen', 'darkgrey', 'darkkhaki', 'darkmagenta', 'darkolivegreen', 'darkorange', 'darkorchid', 'darkred', 'darksalmon', 'darkseagreen', 'darkslateblue', 'darkslategray', 'darkslategrey', 'darkturquoise', 'darkviolet', 'deeppink', 'deepskyblue', 'dimgray', 'dimgrey', 'dodgerblue', 'firebrick', 'floralwhite', 'forestgreen', 'gainsboro', 'ghostwhite', 'gold', 'goldenrod', 'greenyellow', 'grey', 'honeydew', 'hotpink', 'indianred', 'indigo', 'ivory', 'khaki', 'lavender', 'lavenderblush', 'lawngreen', 'lemonchiffon', 'lightblue', 'lightcoral', 'lightcyan', 'lightgoldenrodyellow', 'lightgray', 'lightgreen', 'lightgrey', 'lightpink', 'lightsalmon', 'lightseagreen', 'lightskyblue', 'lightslategray', 'lightslategrey', 'lightsteelblue', 'lightyellow', 'limegreen', 'linen', 'magenta', 'mediumaquamarine', 'mediumblue', 'mediumorchid', 'mediumpurple', 'mediumseagreen', 'mediumslateblue', 'mediumspringgreen', 'mediumturquoise', 'mediumvioletred', 'midnightblue', 'mintcream', 'mistyrose', 'moccasin', 'navajowhite', 'oldlace', 'olivedrab', 'orangered', 'orchid', 'palegoldenrod', 'palegreen', 'paleturquoise', 'palevioletred', 'papayawhip', 'peachpuff', 'peru', 'pink', 'plum', 'powderblue', 'rosybrown', 'royalblue', 'saddlebrown', 'salmon', 'sandybrown', 'seagreen', 'seashell', 'sienna', 'skyblue', 'slateblue', 'slategray', 'slategrey', 'snow', 'springgreen', 'steelblue', 'tan', 'thistle', 'tomato', 'turquoise', 'violet', 'wheat', 'whitesmoke', 'yellowgreen', 'rebeccapurple'];
|
|
8
8
|
var legacyColors = ['R50', 'R75', 'R100', 'R200', 'R300', 'R400', 'R500', 'Y50', 'Y75', 'Y100', 'Y200', 'Y300', 'Y400', 'Y500', 'G50', 'G75', 'G100', 'G200', 'G300', 'G400', 'G500', 'B50', 'B75', 'B100', 'B200', 'B300', 'B400', 'B500', 'P50', 'P75', 'P100', 'P200', 'P300', 'P400', 'P500', 'T50', 'T75', 'T100', 'T200', 'T300', 'T400', 'T500', 'N0', 'N10', 'N20', 'N30', 'N40', 'N50', 'N60', 'N70', 'N80', 'N90', 'N100', 'N200', 'N300', 'N400', 'N500', 'N600', 'N700', 'N800', 'N900', 'N10A', 'N20A', 'N30A', 'N40A', 'N50A', 'N60A', 'N70A', 'N80A', 'N90A', 'N100A', 'N200A', 'N300A', 'N400A', 'N500A', 'N600A', 'N700A', 'N800A', 'DN900', 'DN800', 'DN700', 'DN600', 'DN500', 'DN400', 'DN300', 'DN200', 'DN100', 'DN90', 'DN80', 'DN70', 'DN60', 'DN50', 'DN40', 'DN30', 'DN20', 'DN10', 'DN0', 'DN800A', 'DN700A', 'DN600A', 'DN500A', 'DN400A', 'DN300A', 'DN200A', 'DN100A', 'DN90A', 'DN80A', 'DN70A', 'DN60A', 'DN50A', 'DN40A', 'DN30A', 'DN20A', 'DN10A'];
|
|
9
9
|
var legacyColorMixins = ['background', 'backgroundActive', 'backgroundHover', 'backgroundOnLayer', 'text', 'textHover', 'textActive', 'subtleText', 'placeholderText', 'heading', 'subtleHeading', 'codeBlock', 'link', 'linkHover', 'linkActive', 'linkOutline', 'primary', 'blue', 'teal', 'purple', 'red', 'yellow', 'green', 'skeleton'];
|
|
@@ -56,7 +56,8 @@ var isHardCodedColor = function isHardCodedColor(value) {
|
|
|
56
56
|
return true;
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
if (value.startsWith('#') && (
|
|
59
|
+
if (value.startsWith('#') && ( // short hex, hex, or hex with alpha
|
|
60
|
+
value.length === 4 || value.length === 7 || value.length === 9)) {
|
|
60
61
|
return true;
|
|
61
62
|
}
|
|
62
63
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.
|
|
6
|
+
exports.isStyledTemplateNode = exports.isStyledObjectNode = exports.isDecendantOfType = exports.isDecendantOfStyleJsxAttribute = exports.isDecendantOfStyleBlock = exports.isDecendantOfGlobalToken = exports.isChildOfType = exports.getClosestNodeOfType = void 0;
|
|
7
7
|
|
|
8
8
|
var isDecendantOfGlobalToken = function isDecendantOfGlobalToken(node) {
|
|
9
9
|
if (node.type === 'CallExpression' && node.callee.type === 'Identifier' && node.callee.name === 'token') {
|
|
@@ -50,6 +50,18 @@ var isDecendantOfStyleJsxAttribute = function isDecendantOfStyleJsxAttribute(nod
|
|
|
50
50
|
|
|
51
51
|
exports.isDecendantOfStyleJsxAttribute = isDecendantOfStyleJsxAttribute;
|
|
52
52
|
|
|
53
|
+
var isStyledTemplateNode = function isStyledTemplateNode(node) {
|
|
54
|
+
return (node === null || node === void 0 ? void 0 : node.type) === 'TaggedTemplateExpression' && node.tag.type === 'MemberExpression' && node.tag.object.type === 'Identifier' && node.tag.object.name === 'styled';
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
exports.isStyledTemplateNode = isStyledTemplateNode;
|
|
58
|
+
|
|
59
|
+
var isStyledObjectNode = function isStyledObjectNode(node) {
|
|
60
|
+
return (node === null || node === void 0 ? void 0 : node.type) === 'CallExpression' && node.callee.type === 'MemberExpression' && node.callee.object.type === 'Identifier' && node.callee.object.name === 'styled';
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
exports.isStyledObjectNode = isStyledObjectNode;
|
|
64
|
+
|
|
53
65
|
var isDecendantOfStyleBlock = function isDecendantOfStyleBlock(node) {
|
|
54
66
|
if (node.type === 'VariableDeclarator') {
|
|
55
67
|
if (node.id.type !== 'Identifier') {
|
|
@@ -81,7 +93,7 @@ var isDecendantOfStyleBlock = function isDecendantOfStyleBlock(node) {
|
|
|
81
93
|
return true;
|
|
82
94
|
}
|
|
83
95
|
|
|
84
|
-
if (node
|
|
96
|
+
if (isStyledTemplateNode(node)) {
|
|
85
97
|
return true;
|
|
86
98
|
}
|
|
87
99
|
|
|
@@ -101,5 +113,23 @@ exports.isDecendantOfStyleBlock = isDecendantOfStyleBlock;
|
|
|
101
113
|
var isChildOfType = function isChildOfType(node, type) {
|
|
102
114
|
return node.parent.type === type;
|
|
103
115
|
};
|
|
116
|
+
/**
|
|
117
|
+
* Given a node, walk up the tree until there is no parent OR a common ancestor of the correct type is found
|
|
118
|
+
*/
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
exports.isChildOfType = isChildOfType;
|
|
122
|
+
|
|
123
|
+
var getClosestNodeOfType = function getClosestNodeOfType(node, type) {
|
|
124
|
+
if (!node) {
|
|
125
|
+
return node;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (node.type === type) {
|
|
129
|
+
return node;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return getClosestNodeOfType(node.parent, type);
|
|
133
|
+
};
|
|
104
134
|
|
|
105
|
-
exports.
|
|
135
|
+
exports.getClosestNodeOfType = getClosestNodeOfType;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.removeNamedImport = void 0;
|
|
7
|
+
|
|
8
|
+
/* eslint-disable import/no-unresolved */
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @param {SourceCode} source The eslint source
|
|
12
|
+
* @param {string} path The path specified to find
|
|
13
|
+
* @returns FixerObject
|
|
14
|
+
*/
|
|
15
|
+
var removeNamedImport = function removeNamedImport(fixer, importNode, name) {
|
|
16
|
+
var filteredSpecifers = importNode.specifiers.filter(function (node) {
|
|
17
|
+
return node.type === 'ImportSpecifier' && node.imported.name !== name;
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
if (filteredSpecifers.length) {
|
|
21
|
+
return fixer.remove(importNode.specifiers.find(function (node) {
|
|
22
|
+
return node.type === 'ImportSpecifier' && node.imported.name === name;
|
|
23
|
+
}));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return fixer.remove(importNode);
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
exports.removeNamedImport = removeNamedImport;
|
package/dist/cjs/version.json
CHANGED
package/dist/es2019/index.js
CHANGED
|
@@ -1,16 +1,24 @@
|
|
|
1
1
|
import ensureTokenUsage from './rules/ensure-design-token-usage';
|
|
2
|
+
import noDeprecatedAPIs from './rules/no-deprecated-apis';
|
|
3
|
+
import noDeprecatedUsage from './rules/no-deprecated-design-token-usage';
|
|
2
4
|
import noDeprecatedImports from './rules/no-deprecated-imports';
|
|
3
5
|
import noUnsafeUsage from './rules/no-unsafe-design-token-usage';
|
|
6
|
+
import useVisuallyHidden from './rules/use-visually-hidden';
|
|
4
7
|
export const rules = {
|
|
5
8
|
'ensure-design-token-usage': ensureTokenUsage,
|
|
6
9
|
'no-unsafe-design-token-usage': noUnsafeUsage,
|
|
7
|
-
'no-deprecated-
|
|
10
|
+
'no-deprecated-design-token-usage': noDeprecatedUsage,
|
|
11
|
+
'no-deprecated-imports': noDeprecatedImports,
|
|
12
|
+
'no-deprecated-apis': noDeprecatedAPIs,
|
|
13
|
+
'use-visually-hidden': useVisuallyHidden
|
|
8
14
|
};
|
|
9
15
|
export const configs = {
|
|
10
16
|
recommended: {
|
|
11
17
|
plugins: ['@atlaskit/design-system'],
|
|
12
18
|
rules: {
|
|
13
|
-
'@atlaskit/design-system/no-deprecated-imports': 'error'
|
|
19
|
+
'@atlaskit/design-system/no-deprecated-imports': 'error',
|
|
20
|
+
'@atlaskit/design-system/use-visually-hidden': 'error',
|
|
21
|
+
'@atlaskit/design-system/no-deprecated-apis': 'warn'
|
|
14
22
|
}
|
|
15
23
|
}
|
|
16
24
|
};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// eslint-disable-next-line import/no-unresolved
|
|
2
|
+
import { getImportedNodeBySource } from '../utils/get-import-node-by-source';
|
|
3
|
+
import { getClosestNodeOfType } from '../utils/is-node';
|
|
4
|
+
const unsafeOverridesConfig = {
|
|
5
|
+
cssFn: ['@atlaskit/menu', '@atlaskit/side-navigation'],
|
|
6
|
+
overrides: ['@atlaskit/drawer', '@atlaskit/menu', '@atlaskit/side-navigation']
|
|
7
|
+
};
|
|
8
|
+
const unsafeOverrides = ['cssFn', 'overrides'];
|
|
9
|
+
const rule = {
|
|
10
|
+
meta: {
|
|
11
|
+
type: 'suggestion',
|
|
12
|
+
docs: {
|
|
13
|
+
description: 'Disallow specified APIs that have been marked as deprecated and/or discouraged.',
|
|
14
|
+
recommended: true
|
|
15
|
+
},
|
|
16
|
+
messages: {
|
|
17
|
+
noDeprecatedApis: `The prop "{{propName}}" has been deprecated. It will be removed in the next major release.`
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
|
|
21
|
+
create(context) {
|
|
22
|
+
return {
|
|
23
|
+
// find JSX atribute - find name of attribute - get source and find relevant identifiers.
|
|
24
|
+
JSXAttribute(node) {
|
|
25
|
+
var _node$name, _closesetJSXElement$n;
|
|
26
|
+
|
|
27
|
+
if (!unsafeOverrides.includes(node === null || node === void 0 ? void 0 : (_node$name = node.name) === null || _node$name === void 0 ? void 0 : _node$name.name)) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const source = context.getSourceCode();
|
|
32
|
+
const bannedApi = node.name.name; // traverse the tree to the nearest JSX Element and get its name
|
|
33
|
+
|
|
34
|
+
const closesetJSXElement = getClosestNodeOfType(node, 'JSXOpeningElement'); // @ts-ignore
|
|
35
|
+
|
|
36
|
+
const jsxElementName = closesetJSXElement === null || closesetJSXElement === void 0 ? void 0 : (_closesetJSXElement$n = closesetJSXElement.name) === null || _closesetJSXElement$n === void 0 ? void 0 : _closesetJSXElement$n.name;
|
|
37
|
+
|
|
38
|
+
if (!jsxElementName) {
|
|
39
|
+
return;
|
|
40
|
+
} // find an import for the path of the banned api
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
unsafeOverridesConfig[bannedApi].forEach(path => {
|
|
44
|
+
const importNode = getImportedNodeBySource(source, path);
|
|
45
|
+
|
|
46
|
+
if (!importNode) {
|
|
47
|
+
return;
|
|
48
|
+
} // find an import that matches our JSX element
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
const hasTargetNode = importNode.specifiers.some(node => node.local.name === jsxElementName);
|
|
52
|
+
|
|
53
|
+
if (!hasTargetNode) {
|
|
54
|
+
return;
|
|
55
|
+
} // if we're here the import exists and there is a valid lint error.
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
context.report({
|
|
59
|
+
node: node,
|
|
60
|
+
messageId: 'noDeprecatedApis',
|
|
61
|
+
data: {
|
|
62
|
+
propName: bannedApi
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
};
|
|
72
|
+
export default rule;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import renameMapping from '@atlaskit/tokens/rename-mapping';
|
|
2
|
+
|
|
3
|
+
const getCleanPathId = path => path.split('.').filter(el => el !== '[default]').join('.');
|
|
4
|
+
|
|
5
|
+
const rule = {
|
|
6
|
+
meta: {
|
|
7
|
+
docs: {
|
|
8
|
+
recommended: true
|
|
9
|
+
},
|
|
10
|
+
fixable: 'code',
|
|
11
|
+
type: 'problem',
|
|
12
|
+
messages: {
|
|
13
|
+
tokenRenamed: 'The token "{{name}}" is deprecated in favour of "{{replacement}}".'
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
|
|
17
|
+
create(context) {
|
|
18
|
+
return {
|
|
19
|
+
'CallExpression[callee.name="token"]': node => {
|
|
20
|
+
if (node.type !== 'CallExpression') {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (node.arguments[0].type !== 'Literal') {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const tokenKey = node.arguments[0].value;
|
|
29
|
+
|
|
30
|
+
if (!tokenKey) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (typeof tokenKey !== 'string') {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const migrationMeta = renameMapping.filter(t => t.state === 'deprecated').find(t => t.path === tokenKey);
|
|
39
|
+
|
|
40
|
+
if (migrationMeta) {
|
|
41
|
+
const cleanTokenKey = getCleanPathId(migrationMeta.replacement);
|
|
42
|
+
context.report({
|
|
43
|
+
messageId: 'tokenRenamed',
|
|
44
|
+
node,
|
|
45
|
+
data: {
|
|
46
|
+
name: tokenKey,
|
|
47
|
+
replacement: cleanTokenKey
|
|
48
|
+
},
|
|
49
|
+
fix: fixer => fixer.replaceText(node.arguments[0], `'${cleanTokenKey}'`)
|
|
50
|
+
});
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
};
|
|
58
|
+
export default rule;
|