@atlaskit/eslint-plugin-design-system 4.10.0 → 4.10.1
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 +8 -0
- package/dist/cjs/rules/no-raw-spacing-values/index.js +58 -13
- package/dist/cjs/rules/no-raw-spacing-values/utils.js +44 -7
- package/dist/cjs/version.json +1 -1
- package/dist/es2019/rules/no-raw-spacing-values/index.js +41 -15
- package/dist/es2019/rules/no-raw-spacing-values/utils.js +33 -4
- package/dist/es2019/version.json +1 -1
- package/dist/esm/rules/no-raw-spacing-values/index.js +60 -14
- package/dist/esm/rules/no-raw-spacing-values/utils.js +35 -4
- package/dist/esm/version.json +1 -1
- package/dist/types/rules/no-raw-spacing-values/utils.d.ts +4 -2
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# @atlaskit/eslint-plugin-design-system
|
|
2
2
|
|
|
3
|
+
## 4.10.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [`d76851b2f42`](https://bitbucket.org/atlassian/atlassian-frontend/commits/d76851b2f42) - Improved NaN handling and output
|
|
8
|
+
- [`0544fe823d1`](https://bitbucket.org/atlassian/atlassian-frontend/commits/0544fe823d1) - Updates to account for nested unary selectors.
|
|
9
|
+
- [`1ed3db0c9be`](https://bitbucket.org/atlassian/atlassian-frontend/commits/1ed3db0c9be) - Improvements to lint rule and accounting for edge cases
|
|
10
|
+
|
|
3
11
|
## 4.10.0
|
|
4
12
|
|
|
5
13
|
### Minor Changes
|
|
@@ -13,6 +13,12 @@ var _eslintCodemodUtils = require("eslint-codemod-utils");
|
|
|
13
13
|
|
|
14
14
|
var _utils = require("./utils");
|
|
15
15
|
|
|
16
|
+
function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
|
|
17
|
+
|
|
18
|
+
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
|
|
19
|
+
|
|
20
|
+
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
|
|
21
|
+
|
|
16
22
|
var rule = {
|
|
17
23
|
meta: {
|
|
18
24
|
type: 'problem',
|
|
@@ -33,7 +39,7 @@ var rule = {
|
|
|
33
39
|
return;
|
|
34
40
|
}
|
|
35
41
|
/**
|
|
36
|
-
* We do this in case
|
|
42
|
+
* We do this in case the fontSize for a style object is declared alongside the `em` or `lineHeight` declaration
|
|
37
43
|
*/
|
|
38
44
|
|
|
39
45
|
|
|
@@ -64,26 +70,36 @@ var rule = {
|
|
|
64
70
|
return;
|
|
65
71
|
}
|
|
66
72
|
|
|
73
|
+
if (node.value.type === 'Literal' && !(0, _utils.isValidSpacingValue)(node.value.value, fontSize)) {
|
|
74
|
+
context.report({
|
|
75
|
+
node: node,
|
|
76
|
+
messageId: 'noRawSpacingValues',
|
|
77
|
+
data: {
|
|
78
|
+
payload: "NaN:".concat(node.value.value)
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
67
84
|
var value = (0, _utils.getValue)(node.value, context);
|
|
68
85
|
|
|
69
|
-
if (value) {
|
|
86
|
+
if (value && (0, _utils.isValidSpacingValue)(value, fontSize)) {
|
|
70
87
|
var values = typeof value === 'number' || typeof value === 'string' ? [value] : value;
|
|
71
|
-
values.forEach(function (
|
|
88
|
+
values.forEach(function (val) {
|
|
72
89
|
context.report({
|
|
73
90
|
node: node,
|
|
74
91
|
messageId: 'noRawSpacingValues',
|
|
75
92
|
data: {
|
|
76
|
-
payload: "".concat(node.key.name, ":").concat((0, _utils.emToPixels)(
|
|
93
|
+
payload: "".concat(node.key.name, ":").concat((0, _utils.emToPixels)(val, fontSize))
|
|
77
94
|
}
|
|
78
95
|
});
|
|
79
96
|
});
|
|
80
|
-
return;
|
|
81
97
|
} else {
|
|
82
98
|
context.report({
|
|
83
99
|
node: node,
|
|
84
100
|
messageId: 'noRawSpacingValues',
|
|
85
101
|
data: {
|
|
86
|
-
payload: "".concat(
|
|
102
|
+
payload: "NaN:".concat(value)
|
|
87
103
|
}
|
|
88
104
|
});
|
|
89
105
|
}
|
|
@@ -106,7 +122,9 @@ var rule = {
|
|
|
106
122
|
* Adapted from ensure-design-token-usage
|
|
107
123
|
*/
|
|
108
124
|
|
|
109
|
-
var cssProperties = combinedString.
|
|
125
|
+
var cssProperties = combinedString.split('\n').filter(function (line) {
|
|
126
|
+
return !line.trim().startsWith('@');
|
|
127
|
+
}).join('\n').replace(/\n/g, '').split(/;|{|}/).map(function (el) {
|
|
110
128
|
return el.trim() || '';
|
|
111
129
|
});
|
|
112
130
|
cssProperties.map(function (style) {
|
|
@@ -115,14 +133,41 @@ var rule = {
|
|
|
115
133
|
property = _style$split2[0],
|
|
116
134
|
value = _style$split2[1];
|
|
117
135
|
|
|
136
|
+
property = (0, _utils.convertHyphenatedNameToCamelCase)(property);
|
|
137
|
+
|
|
118
138
|
if ((0, _utils.isSpacingProperty)(property)) {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
139
|
+
if ((0, _utils.isValidSpacingValue)(value)) {
|
|
140
|
+
var values = (0, _utils.getValueFromShorthand)(value);
|
|
141
|
+
|
|
142
|
+
var _iterator = _createForOfIteratorHelper(values),
|
|
143
|
+
_step;
|
|
144
|
+
|
|
145
|
+
try {
|
|
146
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
147
|
+
var val = _step.value;
|
|
148
|
+
// could be array of values e.g. padding: 8px 12px 3px
|
|
149
|
+
context.report({
|
|
150
|
+
node: node,
|
|
151
|
+
messageId: 'noRawSpacingValues',
|
|
152
|
+
data: {
|
|
153
|
+
payload: "".concat(property, ":").concat(val)
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
} catch (err) {
|
|
158
|
+
_iterator.e(err);
|
|
159
|
+
} finally {
|
|
160
|
+
_iterator.f();
|
|
124
161
|
}
|
|
125
|
-
}
|
|
162
|
+
} else {
|
|
163
|
+
context.report({
|
|
164
|
+
node: node,
|
|
165
|
+
messageId: 'noRawSpacingValues',
|
|
166
|
+
data: {
|
|
167
|
+
payload: "NaN:".concat(value)
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
}
|
|
126
171
|
}
|
|
127
172
|
|
|
128
173
|
return;
|
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.emToPixels = void 0;
|
|
6
|
+
exports.emToPixels = exports.convertHyphenatedNameToCamelCase = void 0;
|
|
7
7
|
exports.findIdentifierInParentScope = findIdentifierInParentScope;
|
|
8
|
-
exports.removePixelSuffix = exports.isSpacingProperty = exports.getValueFromShorthand = exports.getValue = void 0;
|
|
8
|
+
exports.removePixelSuffix = exports.isValidSpacingValue = exports.isSpacingProperty = exports.getValueFromShorthand = exports.getValue = void 0;
|
|
9
9
|
|
|
10
10
|
var _eslintCodemodUtils = require("eslint-codemod-utils");
|
|
11
11
|
|
|
12
|
-
var properties = ['padding', 'paddingLeft', 'paddingTop', 'paddingRight', 'paddingBottom', 'marginLeft', 'marginTop', 'marginRight', 'marginBottom', 'margin', 'gap', 'fontSize', 'lineHeight', 'width', 'height'];
|
|
12
|
+
var properties = ['padding', 'paddingLeft', 'paddingTop', 'paddingRight', 'paddingBottom', 'marginLeft', 'marginTop', 'marginRight', 'marginBottom', 'margin', 'gap', 'fontSize', 'lineHeight', 'width', 'height', 'rowGap', 'gridRowGap', 'columnGap', 'gridColumnGap'];
|
|
13
13
|
|
|
14
14
|
function findIdentifierInParentScope(_ref) {
|
|
15
15
|
var scope = _ref.scope,
|
|
@@ -123,6 +123,10 @@ var getValueFromIdentifier = function getValueFromIdentifier(node, context) {
|
|
|
123
123
|
|
|
124
124
|
var definition = variable.defs[0];
|
|
125
125
|
|
|
126
|
+
if ((0, _eslintCodemodUtils.isNodeOfType)(definition.node, 'ImportSpecifier') && (0, _eslintCodemodUtils.isNodeOfType)(definition.node.parent, 'ImportDeclaration') && definition.node.parent.source.value === '@atlassian/jira-common-legacy-do-not-add-anything-new/src/styles') {
|
|
127
|
+
return definition.node.imported.name === 'gridSize' ? 8 : null;
|
|
128
|
+
}
|
|
129
|
+
|
|
126
130
|
if (!(0, _eslintCodemodUtils.isNodeOfType)(definition.node, 'VariableDeclarator')) {
|
|
127
131
|
return null;
|
|
128
132
|
}
|
|
@@ -146,7 +150,7 @@ var getValueFromUnaryExpression = function getValueFromUnaryExpression(node, con
|
|
|
146
150
|
} // eslint-disable-next-line no-eval
|
|
147
151
|
|
|
148
152
|
|
|
149
|
-
return eval("".concat(node.operator).concat(value));
|
|
153
|
+
return eval("".concat(node.operator, "(").concat(value, ")"));
|
|
150
154
|
};
|
|
151
155
|
/**
|
|
152
156
|
* @example
|
|
@@ -198,9 +202,9 @@ var emToPixels = function emToPixels(value, fontSize) {
|
|
|
198
202
|
|
|
199
203
|
if (match && typeof fontSize === 'number') {
|
|
200
204
|
return Number(match[1]) * fontSize;
|
|
205
|
+
} else {
|
|
206
|
+
return null;
|
|
201
207
|
}
|
|
202
|
-
|
|
203
|
-
return 'NaN';
|
|
204
208
|
}
|
|
205
209
|
|
|
206
210
|
return value;
|
|
@@ -220,4 +224,37 @@ var removePixelSuffix = function removePixelSuffix(value) {
|
|
|
220
224
|
return Number(isString ? value.replace('px', '') : value);
|
|
221
225
|
};
|
|
222
226
|
|
|
223
|
-
exports.removePixelSuffix = removePixelSuffix;
|
|
227
|
+
exports.removePixelSuffix = removePixelSuffix;
|
|
228
|
+
var invalidSpacingUnitRegex = /(%$)|(\d+rem$)|(^calc)|(vw$)|(vh$)/;
|
|
229
|
+
|
|
230
|
+
var isValidSpacingValue = function isValidSpacingValue(value, fontSize) {
|
|
231
|
+
if (typeof value === 'string') {
|
|
232
|
+
if (invalidSpacingUnitRegex.test(value)) {
|
|
233
|
+
return false;
|
|
234
|
+
}
|
|
235
|
+
} else if (Array.isArray(value)) {
|
|
236
|
+
// could be array due to shorthand
|
|
237
|
+
for (var val in value) {
|
|
238
|
+
if (invalidSpacingUnitRegex.test(val)) {
|
|
239
|
+
return false;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if (emRegex.test(value) && typeof fontSize !== 'number') {
|
|
245
|
+
return false;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
return true;
|
|
249
|
+
}; // convert line-height to lineHeight
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
exports.isValidSpacingValue = isValidSpacingValue;
|
|
253
|
+
|
|
254
|
+
var convertHyphenatedNameToCamelCase = function convertHyphenatedNameToCamelCase(prop) {
|
|
255
|
+
return prop.replace(/-./g, function (m) {
|
|
256
|
+
return m[1].toUpperCase();
|
|
257
|
+
});
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
exports.convertHyphenatedNameToCamelCase = convertHyphenatedNameToCamelCase;
|
package/dist/cjs/version.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { isNodeOfType } from 'eslint-codemod-utils';
|
|
2
|
-
import { emToPixels, getValue, isSpacingProperty,
|
|
2
|
+
import { convertHyphenatedNameToCamelCase, emToPixels, getValue, getValueFromShorthand, isSpacingProperty, isValidSpacingValue } from './utils';
|
|
3
3
|
const rule = {
|
|
4
4
|
meta: {
|
|
5
5
|
type: 'problem',
|
|
@@ -21,7 +21,7 @@ const rule = {
|
|
|
21
21
|
return;
|
|
22
22
|
}
|
|
23
23
|
/**
|
|
24
|
-
* We do this in case
|
|
24
|
+
* We do this in case the fontSize for a style object is declared alongside the `em` or `lineHeight` declaration
|
|
25
25
|
*/
|
|
26
26
|
|
|
27
27
|
|
|
@@ -52,26 +52,36 @@ const rule = {
|
|
|
52
52
|
return;
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
+
if (node.value.type === 'Literal' && !isValidSpacingValue(node.value.value, fontSize)) {
|
|
56
|
+
context.report({
|
|
57
|
+
node,
|
|
58
|
+
messageId: 'noRawSpacingValues',
|
|
59
|
+
data: {
|
|
60
|
+
payload: `NaN:${node.value.value}`
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
55
66
|
const value = getValue(node.value, context);
|
|
56
67
|
|
|
57
|
-
if (value) {
|
|
68
|
+
if (value && isValidSpacingValue(value, fontSize)) {
|
|
58
69
|
const values = typeof value === 'number' || typeof value === 'string' ? [value] : value;
|
|
59
|
-
values.forEach(
|
|
70
|
+
values.forEach(val => {
|
|
60
71
|
context.report({
|
|
61
72
|
node,
|
|
62
73
|
messageId: 'noRawSpacingValues',
|
|
63
74
|
data: {
|
|
64
|
-
payload: `${node.key.name}:${emToPixels(
|
|
75
|
+
payload: `${node.key.name}:${emToPixels(val, fontSize)}`
|
|
65
76
|
}
|
|
66
77
|
});
|
|
67
78
|
});
|
|
68
|
-
return;
|
|
69
79
|
} else {
|
|
70
80
|
context.report({
|
|
71
81
|
node,
|
|
72
82
|
messageId: 'noRawSpacingValues',
|
|
73
83
|
data: {
|
|
74
|
-
payload:
|
|
84
|
+
payload: `NaN:${value}`
|
|
75
85
|
}
|
|
76
86
|
});
|
|
77
87
|
}
|
|
@@ -94,18 +104,34 @@ const rule = {
|
|
|
94
104
|
* Adapted from ensure-design-token-usage
|
|
95
105
|
*/
|
|
96
106
|
|
|
97
|
-
const cssProperties = combinedString.replace(/\n/g, '').split(/;|{|}/).map(el => el.trim() || '');
|
|
107
|
+
const cssProperties = combinedString.split('\n').filter(line => !line.trim().startsWith('@')).join('\n').replace(/\n/g, '').split(/;|{|}/).map(el => el.trim() || '');
|
|
98
108
|
cssProperties.map(style => {
|
|
99
|
-
|
|
109
|
+
let [property, value] = style.split(':');
|
|
110
|
+
property = convertHyphenatedNameToCamelCase(property);
|
|
100
111
|
|
|
101
112
|
if (isSpacingProperty(property)) {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
113
|
+
if (isValidSpacingValue(value)) {
|
|
114
|
+
const values = getValueFromShorthand(value);
|
|
115
|
+
|
|
116
|
+
for (const val of values) {
|
|
117
|
+
// could be array of values e.g. padding: 8px 12px 3px
|
|
118
|
+
context.report({
|
|
119
|
+
node,
|
|
120
|
+
messageId: 'noRawSpacingValues',
|
|
121
|
+
data: {
|
|
122
|
+
payload: `${property}:${val}`
|
|
123
|
+
}
|
|
124
|
+
});
|
|
107
125
|
}
|
|
108
|
-
}
|
|
126
|
+
} else {
|
|
127
|
+
context.report({
|
|
128
|
+
node,
|
|
129
|
+
messageId: 'noRawSpacingValues',
|
|
130
|
+
data: {
|
|
131
|
+
payload: `NaN:${value}`
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
}
|
|
109
135
|
}
|
|
110
136
|
|
|
111
137
|
return;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { isNodeOfType } from 'eslint-codemod-utils';
|
|
2
|
-
const properties = ['padding', 'paddingLeft', 'paddingTop', 'paddingRight', 'paddingBottom', 'marginLeft', 'marginTop', 'marginRight', 'marginBottom', 'margin', 'gap', 'fontSize', 'lineHeight', 'width', 'height'];
|
|
2
|
+
const properties = ['padding', 'paddingLeft', 'paddingTop', 'paddingRight', 'paddingBottom', 'marginLeft', 'marginTop', 'marginRight', 'marginBottom', 'margin', 'gap', 'fontSize', 'lineHeight', 'width', 'height', 'rowGap', 'gridRowGap', 'columnGap', 'gridColumnGap'];
|
|
3
3
|
export function findIdentifierInParentScope({
|
|
4
4
|
scope,
|
|
5
5
|
identifierName
|
|
@@ -97,6 +97,10 @@ const getValueFromIdentifier = (node, context) => {
|
|
|
97
97
|
|
|
98
98
|
const definition = variable.defs[0];
|
|
99
99
|
|
|
100
|
+
if (isNodeOfType(definition.node, 'ImportSpecifier') && isNodeOfType(definition.node.parent, 'ImportDeclaration') && definition.node.parent.source.value === '@atlassian/jira-common-legacy-do-not-add-anything-new/src/styles') {
|
|
101
|
+
return definition.node.imported.name === 'gridSize' ? 8 : null;
|
|
102
|
+
}
|
|
103
|
+
|
|
100
104
|
if (!isNodeOfType(definition.node, 'VariableDeclarator')) {
|
|
101
105
|
return null;
|
|
102
106
|
}
|
|
@@ -120,7 +124,7 @@ const getValueFromUnaryExpression = (node, context) => {
|
|
|
120
124
|
} // eslint-disable-next-line no-eval
|
|
121
125
|
|
|
122
126
|
|
|
123
|
-
return eval(`${node.operator}${value}`);
|
|
127
|
+
return eval(`${node.operator}(${value})`);
|
|
124
128
|
};
|
|
125
129
|
/**
|
|
126
130
|
* @example
|
|
@@ -173,9 +177,9 @@ export const emToPixels = (value, fontSize) => {
|
|
|
173
177
|
|
|
174
178
|
if (match && typeof fontSize === 'number') {
|
|
175
179
|
return Number(match[1]) * fontSize;
|
|
180
|
+
} else {
|
|
181
|
+
return null;
|
|
176
182
|
}
|
|
177
|
-
|
|
178
|
-
return 'NaN';
|
|
179
183
|
}
|
|
180
184
|
|
|
181
185
|
return value;
|
|
@@ -190,4 +194,29 @@ export const removePixelSuffix = value => {
|
|
|
190
194
|
|
|
191
195
|
|
|
192
196
|
return Number(isString ? value.replace('px', '') : value);
|
|
197
|
+
};
|
|
198
|
+
const invalidSpacingUnitRegex = /(%$)|(\d+rem$)|(^calc)|(vw$)|(vh$)/;
|
|
199
|
+
export const isValidSpacingValue = (value, fontSize) => {
|
|
200
|
+
if (typeof value === 'string') {
|
|
201
|
+
if (invalidSpacingUnitRegex.test(value)) {
|
|
202
|
+
return false;
|
|
203
|
+
}
|
|
204
|
+
} else if (Array.isArray(value)) {
|
|
205
|
+
// could be array due to shorthand
|
|
206
|
+
for (const val in value) {
|
|
207
|
+
if (invalidSpacingUnitRegex.test(val)) {
|
|
208
|
+
return false;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (emRegex.test(value) && typeof fontSize !== 'number') {
|
|
214
|
+
return false;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return true;
|
|
218
|
+
}; // convert line-height to lineHeight
|
|
219
|
+
|
|
220
|
+
export const convertHyphenatedNameToCamelCase = prop => {
|
|
221
|
+
return prop.replace(/-./g, m => m[1].toUpperCase());
|
|
193
222
|
};
|
package/dist/es2019/version.json
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
|
|
2
|
+
|
|
3
|
+
function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
|
|
4
|
+
|
|
5
|
+
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
|
|
6
|
+
|
|
7
|
+
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
|
|
8
|
+
|
|
2
9
|
import { isNodeOfType } from 'eslint-codemod-utils';
|
|
3
|
-
import { emToPixels, getValue, isSpacingProperty,
|
|
10
|
+
import { convertHyphenatedNameToCamelCase, emToPixels, getValue, getValueFromShorthand, isSpacingProperty, isValidSpacingValue } from './utils';
|
|
4
11
|
var rule = {
|
|
5
12
|
meta: {
|
|
6
13
|
type: 'problem',
|
|
@@ -21,7 +28,7 @@ var rule = {
|
|
|
21
28
|
return;
|
|
22
29
|
}
|
|
23
30
|
/**
|
|
24
|
-
* We do this in case
|
|
31
|
+
* We do this in case the fontSize for a style object is declared alongside the `em` or `lineHeight` declaration
|
|
25
32
|
*/
|
|
26
33
|
|
|
27
34
|
|
|
@@ -52,26 +59,36 @@ var rule = {
|
|
|
52
59
|
return;
|
|
53
60
|
}
|
|
54
61
|
|
|
62
|
+
if (node.value.type === 'Literal' && !isValidSpacingValue(node.value.value, fontSize)) {
|
|
63
|
+
context.report({
|
|
64
|
+
node: node,
|
|
65
|
+
messageId: 'noRawSpacingValues',
|
|
66
|
+
data: {
|
|
67
|
+
payload: "NaN:".concat(node.value.value)
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
|
|
55
73
|
var value = getValue(node.value, context);
|
|
56
74
|
|
|
57
|
-
if (value) {
|
|
75
|
+
if (value && isValidSpacingValue(value, fontSize)) {
|
|
58
76
|
var values = typeof value === 'number' || typeof value === 'string' ? [value] : value;
|
|
59
|
-
values.forEach(function (
|
|
77
|
+
values.forEach(function (val) {
|
|
60
78
|
context.report({
|
|
61
79
|
node: node,
|
|
62
80
|
messageId: 'noRawSpacingValues',
|
|
63
81
|
data: {
|
|
64
|
-
payload: "".concat(node.key.name, ":").concat(emToPixels(
|
|
82
|
+
payload: "".concat(node.key.name, ":").concat(emToPixels(val, fontSize))
|
|
65
83
|
}
|
|
66
84
|
});
|
|
67
85
|
});
|
|
68
|
-
return;
|
|
69
86
|
} else {
|
|
70
87
|
context.report({
|
|
71
88
|
node: node,
|
|
72
89
|
messageId: 'noRawSpacingValues',
|
|
73
90
|
data: {
|
|
74
|
-
payload: "".concat(
|
|
91
|
+
payload: "NaN:".concat(value)
|
|
75
92
|
}
|
|
76
93
|
});
|
|
77
94
|
}
|
|
@@ -94,7 +111,9 @@ var rule = {
|
|
|
94
111
|
* Adapted from ensure-design-token-usage
|
|
95
112
|
*/
|
|
96
113
|
|
|
97
|
-
var cssProperties = combinedString.
|
|
114
|
+
var cssProperties = combinedString.split('\n').filter(function (line) {
|
|
115
|
+
return !line.trim().startsWith('@');
|
|
116
|
+
}).join('\n').replace(/\n/g, '').split(/;|{|}/).map(function (el) {
|
|
98
117
|
return el.trim() || '';
|
|
99
118
|
});
|
|
100
119
|
cssProperties.map(function (style) {
|
|
@@ -103,14 +122,41 @@ var rule = {
|
|
|
103
122
|
property = _style$split2[0],
|
|
104
123
|
value = _style$split2[1];
|
|
105
124
|
|
|
125
|
+
property = convertHyphenatedNameToCamelCase(property);
|
|
126
|
+
|
|
106
127
|
if (isSpacingProperty(property)) {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
128
|
+
if (isValidSpacingValue(value)) {
|
|
129
|
+
var values = getValueFromShorthand(value);
|
|
130
|
+
|
|
131
|
+
var _iterator = _createForOfIteratorHelper(values),
|
|
132
|
+
_step;
|
|
133
|
+
|
|
134
|
+
try {
|
|
135
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
136
|
+
var val = _step.value;
|
|
137
|
+
// could be array of values e.g. padding: 8px 12px 3px
|
|
138
|
+
context.report({
|
|
139
|
+
node: node,
|
|
140
|
+
messageId: 'noRawSpacingValues',
|
|
141
|
+
data: {
|
|
142
|
+
payload: "".concat(property, ":").concat(val)
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
} catch (err) {
|
|
147
|
+
_iterator.e(err);
|
|
148
|
+
} finally {
|
|
149
|
+
_iterator.f();
|
|
112
150
|
}
|
|
113
|
-
}
|
|
151
|
+
} else {
|
|
152
|
+
context.report({
|
|
153
|
+
node: node,
|
|
154
|
+
messageId: 'noRawSpacingValues',
|
|
155
|
+
data: {
|
|
156
|
+
payload: "NaN:".concat(value)
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
}
|
|
114
160
|
}
|
|
115
161
|
|
|
116
162
|
return;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { isNodeOfType } from 'eslint-codemod-utils';
|
|
2
|
-
var properties = ['padding', 'paddingLeft', 'paddingTop', 'paddingRight', 'paddingBottom', 'marginLeft', 'marginTop', 'marginRight', 'marginBottom', 'margin', 'gap', 'fontSize', 'lineHeight', 'width', 'height'];
|
|
2
|
+
var properties = ['padding', 'paddingLeft', 'paddingTop', 'paddingRight', 'paddingBottom', 'marginLeft', 'marginTop', 'marginRight', 'marginBottom', 'margin', 'gap', 'fontSize', 'lineHeight', 'width', 'height', 'rowGap', 'gridRowGap', 'columnGap', 'gridColumnGap'];
|
|
3
3
|
export function findIdentifierInParentScope(_ref) {
|
|
4
4
|
var scope = _ref.scope,
|
|
5
5
|
identifierName = _ref.identifierName;
|
|
@@ -104,6 +104,10 @@ var getValueFromIdentifier = function getValueFromIdentifier(node, context) {
|
|
|
104
104
|
|
|
105
105
|
var definition = variable.defs[0];
|
|
106
106
|
|
|
107
|
+
if (isNodeOfType(definition.node, 'ImportSpecifier') && isNodeOfType(definition.node.parent, 'ImportDeclaration') && definition.node.parent.source.value === '@atlassian/jira-common-legacy-do-not-add-anything-new/src/styles') {
|
|
108
|
+
return definition.node.imported.name === 'gridSize' ? 8 : null;
|
|
109
|
+
}
|
|
110
|
+
|
|
107
111
|
if (!isNodeOfType(definition.node, 'VariableDeclarator')) {
|
|
108
112
|
return null;
|
|
109
113
|
}
|
|
@@ -127,7 +131,7 @@ var getValueFromUnaryExpression = function getValueFromUnaryExpression(node, con
|
|
|
127
131
|
} // eslint-disable-next-line no-eval
|
|
128
132
|
|
|
129
133
|
|
|
130
|
-
return eval("".concat(node.operator).concat(value));
|
|
134
|
+
return eval("".concat(node.operator, "(").concat(value, ")"));
|
|
131
135
|
};
|
|
132
136
|
/**
|
|
133
137
|
* @example
|
|
@@ -178,9 +182,9 @@ export var emToPixels = function emToPixels(value, fontSize) {
|
|
|
178
182
|
|
|
179
183
|
if (match && typeof fontSize === 'number') {
|
|
180
184
|
return Number(match[1]) * fontSize;
|
|
185
|
+
} else {
|
|
186
|
+
return null;
|
|
181
187
|
}
|
|
182
|
-
|
|
183
|
-
return 'NaN';
|
|
184
188
|
}
|
|
185
189
|
|
|
186
190
|
return value;
|
|
@@ -195,4 +199,31 @@ export var removePixelSuffix = function removePixelSuffix(value) {
|
|
|
195
199
|
|
|
196
200
|
|
|
197
201
|
return Number(isString ? value.replace('px', '') : value);
|
|
202
|
+
};
|
|
203
|
+
var invalidSpacingUnitRegex = /(%$)|(\d+rem$)|(^calc)|(vw$)|(vh$)/;
|
|
204
|
+
export var isValidSpacingValue = function isValidSpacingValue(value, fontSize) {
|
|
205
|
+
if (typeof value === 'string') {
|
|
206
|
+
if (invalidSpacingUnitRegex.test(value)) {
|
|
207
|
+
return false;
|
|
208
|
+
}
|
|
209
|
+
} else if (Array.isArray(value)) {
|
|
210
|
+
// could be array due to shorthand
|
|
211
|
+
for (var val in value) {
|
|
212
|
+
if (invalidSpacingUnitRegex.test(val)) {
|
|
213
|
+
return false;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
if (emRegex.test(value) && typeof fontSize !== 'number') {
|
|
219
|
+
return false;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
return true;
|
|
223
|
+
}; // convert line-height to lineHeight
|
|
224
|
+
|
|
225
|
+
export var convertHyphenatedNameToCamelCase = function convertHyphenatedNameToCamelCase(prop) {
|
|
226
|
+
return prop.replace(/-./g, function (m) {
|
|
227
|
+
return m[1].toUpperCase();
|
|
228
|
+
});
|
|
198
229
|
};
|
package/dist/esm/version.json
CHANGED
|
@@ -6,6 +6,8 @@ export declare function findIdentifierInParentScope({ scope, identifierName, }:
|
|
|
6
6
|
}): Scope.Variable | null;
|
|
7
7
|
export declare const isSpacingProperty: (prop: string) => boolean;
|
|
8
8
|
export declare const getValueFromShorthand: (str: unknown) => any[];
|
|
9
|
-
export declare const getValue: (node: EslintNode, context: Rule.RuleContext) => number | null |
|
|
10
|
-
export declare const emToPixels: <T extends unknown>(value: T, fontSize: number | null) => number | T |
|
|
9
|
+
export declare const getValue: (node: EslintNode, context: Rule.RuleContext) => string | number | any[] | null | undefined;
|
|
10
|
+
export declare const emToPixels: <T extends unknown>(value: T, fontSize: number | null | undefined) => number | T | null;
|
|
11
11
|
export declare const removePixelSuffix: (value: string | number) => string | number;
|
|
12
|
+
export declare const isValidSpacingValue: (value: string | number | boolean | RegExp | null | undefined | any[] | bigint, fontSize?: number | null | undefined) => boolean;
|
|
13
|
+
export declare const convertHyphenatedNameToCamelCase: (prop: string) => string;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/eslint-plugin-design-system",
|
|
3
3
|
"description": "The essential plugin for use with the Atlassian Design System.",
|
|
4
|
-
"version": "4.10.
|
|
4
|
+
"version": "4.10.1",
|
|
5
5
|
"author": "Atlassian Pty Ltd",
|
|
6
6
|
"publishConfig": {
|
|
7
7
|
"registry": "https://registry.npmjs.org/"
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"@atlaskit/ds-lib": "^2.1.0",
|
|
35
|
-
"@atlaskit/theme": "^12.0
|
|
35
|
+
"@atlaskit/theme": "^12.2.0",
|
|
36
36
|
"@atlassian/atlassian-frontend-prettier-config-1.0.1": "npm:@atlassian/atlassian-frontend-prettier-config@1.0.1",
|
|
37
37
|
"@emotion/core": "^10.0.9",
|
|
38
38
|
"@emotion/styled": "^11.0.0",
|