@atlaskit/eslint-plugin-platform 2.1.0 → 2.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # @atlaskit/eslint-plugin-platform
2
2
 
3
+ ## 2.1.2
4
+
5
+ ### Patch Changes
6
+
7
+ - [#102248](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/102248)
8
+ [`05acb13c43541`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/05acb13c43541) -
9
+ AFB-825 Fixing edge case of expand-spacing-shorthand rule
10
+
11
+ ## 2.1.1
12
+
13
+ ### Patch Changes
14
+
15
+ - [#101753](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/101753)
16
+ [`ab8a4d93399e8`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/ab8a4d93399e8) -
17
+ AFB-822 Turn of expand-spacing-shorthand rule until all of Jira and Platform rollout is complete
18
+
3
19
  ## 2.1.0
4
20
 
5
21
  ### Minor Changes
package/dist/cjs/index.js CHANGED
@@ -72,7 +72,7 @@ var commonConfig = {
72
72
  // Compiled: rules that are not included via `@compiled/recommended
73
73
  '@atlaskit/platform/expand-border-shorthand': 'error',
74
74
  '@atlaskit/platform/expand-background-shorthand': 'error',
75
- '@atlaskit/platform/expand-spacing-shorthand': 'warn',
75
+ '@atlaskit/platform/expand-spacing-shorthand': 'off',
76
76
  '@compiled/jsx-pragma': ['error', {
77
77
  importSources: ['@atlaskit/css'],
78
78
  onlyRunIfImportingCompiled: true,
@@ -11,9 +11,7 @@ var _compiledUtils = require("../../util/compiled-utils");
11
11
  function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, 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 o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
12
12
  function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
13
13
  function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
14
- var spacingPos = ["Top", "Right", "Bottom", "Left"];
15
- ;
16
-
14
+ var spacingPos = ['Top', 'Right', 'Bottom', 'Left'];
17
15
  // Checks if node is a call expression with identifier 'token'
18
16
  var isTokenCallExpression = function isTokenCallExpression(node) {
19
17
  if (node.callee.type === 'Identifier' && node.callee.name === 'token') {
@@ -32,11 +30,12 @@ var parseTemplateLiteral = function parseTemplateLiteral(templateLiteral, contex
32
30
  if (i < quasis.length) {
33
31
  var cookedQuasi = quasis[i].value.cooked;
34
32
  if (cookedQuasi) {
35
- var splitQuasi = cookedQuasi.split(" ").filter(function (str) {
36
- return str.length > 0;
37
- });
38
- splitQuasi.forEach(function (str) {
39
- propertyValues.push(isNaN(Number(str)) ? "'".concat(str, "'") : str);
33
+ var splitQuasis = cookedQuasi.split(' ');
34
+ splitQuasis.forEach(function (str) {
35
+ str = str.trim().replace("\'", "");
36
+ if (str.length > 0) {
37
+ propertyValues.push(isNaN(Number(str)) ? "'".concat(str, "'") : str);
38
+ }
40
39
  });
41
40
  }
42
41
  }
@@ -49,7 +48,7 @@ var parseTemplateLiteral = function parseTemplateLiteral(templateLiteral, contex
49
48
  };
50
49
  var checkValidPropertyValues = function checkValidPropertyValues(propertyValues) {
51
50
  if (!propertyValues.some(function (str) {
52
- return str.includes("token(");
51
+ return str.includes('token(');
53
52
  })) {
54
53
  return false;
55
54
  }
@@ -57,13 +56,23 @@ var checkValidPropertyValues = function checkValidPropertyValues(propertyValues)
57
56
  return false;
58
57
  }
59
58
  if (propertyValues.some(function (str) {
60
- return str.includes("calc(");
59
+ return str.includes('calc(');
61
60
  })) {
62
61
  return false;
63
62
  }
64
63
  return true;
65
64
  };
66
65
 
66
+ // Check that all expressions in TemplateLiteral are token expressions
67
+ // If true: create an autofix
68
+ // If false: report violation without autofix
69
+ var hasOnlyTokens = function hasOnlyTokens(templateLiteral) {
70
+ var expressions = templateLiteral.expressions;
71
+ return expressions.every(function (expr) {
72
+ return expr.type === 'CallExpression' && isTokenCallExpression(expr);
73
+ });
74
+ };
75
+
67
76
  // To fix spacing shorthands, given a list of spacing property values, expands the spacing property and adds autofix fixes
68
77
  var expandSpacingProperties = function expandSpacingProperties(_ref) {
69
78
  var context = _ref.context,
@@ -98,10 +107,10 @@ var expandSpacingProperties = function expandSpacingProperties(_ref) {
98
107
  start = _prop$range[0],
99
108
  end = _prop$range[1];
100
109
  // Remove the entire line for the duplicate property
101
- while ((0, _contextCompat.getSourceCode)(context).text[end] !== "\n") {
110
+ while ((0, _contextCompat.getSourceCode)(context).text[end] !== '\n') {
102
111
  end += 1;
103
112
  }
104
- while ((0, _contextCompat.getSourceCode)(context).text[start] !== "\n") {
113
+ while ((0, _contextCompat.getSourceCode)(context).text[start] !== '\n') {
105
114
  start -= 1;
106
115
  }
107
116
  spacing[i] = (0, _contextCompat.getSourceCode)(context).getText(prop.value);
@@ -130,6 +139,16 @@ var executeExpandSpacingRule = function executeExpandSpacingRule(context, node,
130
139
  }
131
140
  if (node.value.type === 'TemplateLiteral') {
132
141
  // Value of spacing property is a TemplateLiteral type that contains a token, e.g. padding: `0 token('a')`
142
+ if (!hasOnlyTokens(node.value)) {
143
+ context.report({
144
+ node: node,
145
+ messageId: 'expandSpacingShorthand',
146
+ data: {
147
+ property: propertyShorthand
148
+ }
149
+ });
150
+ return;
151
+ }
133
152
  var propertyValues = parseTemplateLiteral(node.value, context);
134
153
  if (!checkValidPropertyValues(propertyValues)) {
135
154
  return;
@@ -64,7 +64,7 @@ const commonConfig = {
64
64
  // Compiled: rules that are not included via `@compiled/recommended
65
65
  '@atlaskit/platform/expand-border-shorthand': 'error',
66
66
  '@atlaskit/platform/expand-background-shorthand': 'error',
67
- '@atlaskit/platform/expand-spacing-shorthand': 'warn',
67
+ '@atlaskit/platform/expand-spacing-shorthand': 'off',
68
68
  '@compiled/jsx-pragma': ['error', {
69
69
  importSources: ['@atlaskit/css'],
70
70
  onlyRunIfImportingCompiled: true,
@@ -1,8 +1,6 @@
1
1
  import { getSourceCode } from '../../util/context-compat';
2
2
  import { isCompiledAPI } from '../../util/compiled-utils';
3
- const spacingPos = ["Top", "Right", "Bottom", "Left"];
4
- ;
5
-
3
+ const spacingPos = ['Top', 'Right', 'Bottom', 'Left'];
6
4
  // Checks if node is a call expression with identifier 'token'
7
5
  const isTokenCallExpression = node => {
8
6
  if (node.callee.type === 'Identifier' && node.callee.name === 'token') {
@@ -21,9 +19,12 @@ const parseTemplateLiteral = (templateLiteral, context) => {
21
19
  if (i < quasis.length) {
22
20
  const cookedQuasi = quasis[i].value.cooked;
23
21
  if (cookedQuasi) {
24
- const splitQuasi = cookedQuasi.split(" ").filter(str => str.length > 0);
25
- splitQuasi.forEach(str => {
26
- propertyValues.push(isNaN(Number(str)) ? `'${str}'` : str);
22
+ const splitQuasis = cookedQuasi.split(' ');
23
+ splitQuasis.forEach(str => {
24
+ str = str.trim().replace("\'", "");
25
+ if (str.length > 0) {
26
+ propertyValues.push(isNaN(Number(str)) ? `'${str}'` : str);
27
+ }
27
28
  });
28
29
  }
29
30
  }
@@ -35,18 +36,26 @@ const parseTemplateLiteral = (templateLiteral, context) => {
35
36
  return propertyValues;
36
37
  };
37
38
  const checkValidPropertyValues = propertyValues => {
38
- if (!propertyValues.some(str => str.includes("token("))) {
39
+ if (!propertyValues.some(str => str.includes('token('))) {
39
40
  return false;
40
41
  }
41
42
  if (propertyValues.length < 1 || propertyValues.length > 4) {
42
43
  return false;
43
44
  }
44
- if (propertyValues.some(str => str.includes("calc("))) {
45
+ if (propertyValues.some(str => str.includes('calc('))) {
45
46
  return false;
46
47
  }
47
48
  return true;
48
49
  };
49
50
 
51
+ // Check that all expressions in TemplateLiteral are token expressions
52
+ // If true: create an autofix
53
+ // If false: report violation without autofix
54
+ const hasOnlyTokens = templateLiteral => {
55
+ const expressions = templateLiteral.expressions;
56
+ return expressions.every(expr => expr.type === 'CallExpression' && isTokenCallExpression(expr));
57
+ };
58
+
50
59
  // To fix spacing shorthands, given a list of spacing property values, expands the spacing property and adds autofix fixes
51
60
  const expandSpacingProperties = ({
52
61
  context,
@@ -69,10 +78,10 @@ const expandSpacingProperties = ({
69
78
  if (prop.key.name === `${propertyShorthand}${spacingPos[i]}`) {
70
79
  let [start, end] = prop.range;
71
80
  // Remove the entire line for the duplicate property
72
- while (getSourceCode(context).text[end] !== "\n") {
81
+ while (getSourceCode(context).text[end] !== '\n') {
73
82
  end += 1;
74
83
  }
75
- while (getSourceCode(context).text[start] !== "\n") {
84
+ while (getSourceCode(context).text[start] !== '\n') {
76
85
  start -= 1;
77
86
  }
78
87
  spacing[i] = getSourceCode(context).getText(prop.value);
@@ -96,6 +105,16 @@ const executeExpandSpacingRule = (context, node, propertyShorthand) => {
96
105
  }
97
106
  if (node.value.type === 'TemplateLiteral') {
98
107
  // Value of spacing property is a TemplateLiteral type that contains a token, e.g. padding: `0 token('a')`
108
+ if (!hasOnlyTokens(node.value)) {
109
+ context.report({
110
+ node,
111
+ messageId: 'expandSpacingShorthand',
112
+ data: {
113
+ property: propertyShorthand
114
+ }
115
+ });
116
+ return;
117
+ }
99
118
  const propertyValues = parseTemplateLiteral(node.value, context);
100
119
  if (!checkValidPropertyValues(propertyValues)) {
101
120
  return;
package/dist/esm/index.js CHANGED
@@ -67,7 +67,7 @@ var commonConfig = {
67
67
  // Compiled: rules that are not included via `@compiled/recommended
68
68
  '@atlaskit/platform/expand-border-shorthand': 'error',
69
69
  '@atlaskit/platform/expand-background-shorthand': 'error',
70
- '@atlaskit/platform/expand-spacing-shorthand': 'warn',
70
+ '@atlaskit/platform/expand-spacing-shorthand': 'off',
71
71
  '@compiled/jsx-pragma': ['error', {
72
72
  importSources: ['@atlaskit/css'],
73
73
  onlyRunIfImportingCompiled: true,
@@ -4,9 +4,7 @@ function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r)
4
4
  function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
5
5
  import { getSourceCode } from '../../util/context-compat';
6
6
  import { isCompiledAPI } from '../../util/compiled-utils';
7
- var spacingPos = ["Top", "Right", "Bottom", "Left"];
8
- ;
9
-
7
+ var spacingPos = ['Top', 'Right', 'Bottom', 'Left'];
10
8
  // Checks if node is a call expression with identifier 'token'
11
9
  var isTokenCallExpression = function isTokenCallExpression(node) {
12
10
  if (node.callee.type === 'Identifier' && node.callee.name === 'token') {
@@ -25,11 +23,12 @@ var parseTemplateLiteral = function parseTemplateLiteral(templateLiteral, contex
25
23
  if (i < quasis.length) {
26
24
  var cookedQuasi = quasis[i].value.cooked;
27
25
  if (cookedQuasi) {
28
- var splitQuasi = cookedQuasi.split(" ").filter(function (str) {
29
- return str.length > 0;
30
- });
31
- splitQuasi.forEach(function (str) {
32
- propertyValues.push(isNaN(Number(str)) ? "'".concat(str, "'") : str);
26
+ var splitQuasis = cookedQuasi.split(' ');
27
+ splitQuasis.forEach(function (str) {
28
+ str = str.trim().replace("\'", "");
29
+ if (str.length > 0) {
30
+ propertyValues.push(isNaN(Number(str)) ? "'".concat(str, "'") : str);
31
+ }
33
32
  });
34
33
  }
35
34
  }
@@ -42,7 +41,7 @@ var parseTemplateLiteral = function parseTemplateLiteral(templateLiteral, contex
42
41
  };
43
42
  var checkValidPropertyValues = function checkValidPropertyValues(propertyValues) {
44
43
  if (!propertyValues.some(function (str) {
45
- return str.includes("token(");
44
+ return str.includes('token(');
46
45
  })) {
47
46
  return false;
48
47
  }
@@ -50,13 +49,23 @@ var checkValidPropertyValues = function checkValidPropertyValues(propertyValues)
50
49
  return false;
51
50
  }
52
51
  if (propertyValues.some(function (str) {
53
- return str.includes("calc(");
52
+ return str.includes('calc(');
54
53
  })) {
55
54
  return false;
56
55
  }
57
56
  return true;
58
57
  };
59
58
 
59
+ // Check that all expressions in TemplateLiteral are token expressions
60
+ // If true: create an autofix
61
+ // If false: report violation without autofix
62
+ var hasOnlyTokens = function hasOnlyTokens(templateLiteral) {
63
+ var expressions = templateLiteral.expressions;
64
+ return expressions.every(function (expr) {
65
+ return expr.type === 'CallExpression' && isTokenCallExpression(expr);
66
+ });
67
+ };
68
+
60
69
  // To fix spacing shorthands, given a list of spacing property values, expands the spacing property and adds autofix fixes
61
70
  var expandSpacingProperties = function expandSpacingProperties(_ref) {
62
71
  var context = _ref.context,
@@ -91,10 +100,10 @@ var expandSpacingProperties = function expandSpacingProperties(_ref) {
91
100
  start = _prop$range[0],
92
101
  end = _prop$range[1];
93
102
  // Remove the entire line for the duplicate property
94
- while (getSourceCode(context).text[end] !== "\n") {
103
+ while (getSourceCode(context).text[end] !== '\n') {
95
104
  end += 1;
96
105
  }
97
- while (getSourceCode(context).text[start] !== "\n") {
106
+ while (getSourceCode(context).text[start] !== '\n') {
98
107
  start -= 1;
99
108
  }
100
109
  spacing[i] = getSourceCode(context).getText(prop.value);
@@ -123,6 +132,16 @@ var executeExpandSpacingRule = function executeExpandSpacingRule(context, node,
123
132
  }
124
133
  if (node.value.type === 'TemplateLiteral') {
125
134
  // Value of spacing property is a TemplateLiteral type that contains a token, e.g. padding: `0 token('a')`
135
+ if (!hasOnlyTokens(node.value)) {
136
+ context.report({
137
+ node: node,
138
+ messageId: 'expandSpacingShorthand',
139
+ data: {
140
+ property: propertyShorthand
141
+ }
142
+ });
143
+ return;
144
+ }
126
145
  var propertyValues = parseTemplateLiteral(node.value, context);
127
146
  if (!checkValidPropertyValues(propertyValues)) {
128
147
  return;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@atlaskit/eslint-plugin-platform",
3
3
  "description": "The essential plugin for use with Atlassian frontend platform tools",
4
- "version": "2.1.0",
4
+ "version": "2.1.2",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "atlassian": {
7
7
  "team": "Build Infra",
package/src/index.tsx CHANGED
@@ -66,7 +66,7 @@ const commonConfig = {
66
66
  // Compiled: rules that are not included via `@compiled/recommended
67
67
  '@atlaskit/platform/expand-border-shorthand': 'error',
68
68
  '@atlaskit/platform/expand-background-shorthand': 'error',
69
- '@atlaskit/platform/expand-spacing-shorthand': 'warn',
69
+ '@atlaskit/platform/expand-spacing-shorthand': 'off',
70
70
  '@compiled/jsx-pragma': [
71
71
  'error',
72
72
  {
@@ -2,15 +2,8 @@ import { outdent } from 'outdent';
2
2
  import { tester } from '../../../../__tests__/utils/_tester';
3
3
  import { expandSpacingShorthand } from '../index';
4
4
 
5
- const included_compiled_libraries = [
6
- '@compiled/react',
7
- '@atlaskit/css'
8
- ];
9
- const exempt_libraries = [
10
- '@atlaskit/primitives',
11
- '@emotion',
12
- 'styled-components',
13
- ];
5
+ const included_compiled_libraries = ['@compiled/react', '@atlaskit/css'];
6
+ const exempt_libraries = ['@emotion/react', 'styled-components'];
14
7
 
15
8
  const validTestCases = (property: string) => {
16
9
  return [
@@ -18,9 +11,14 @@ const validTestCases = (property: string) => {
18
11
  name: `${property}: do not have to handle non-compiled packages (${imp})`,
19
12
  code: outdent`
20
13
  import {css} from '${imp}';
14
+ import {xcss} from '@atlaskit/primitives';
15
+
21
16
  const styles = css({
22
17
  ${property}: token('space.200'),
23
18
  });
19
+ const styles2 = xcss({
20
+ ${property}: token('space.200'),
21
+ });
24
22
  `,
25
23
  })),
26
24
  {
@@ -254,6 +252,26 @@ const invalidTestCases = (property: string) => {
254
252
  `,
255
253
  errors: [{ messageId: 'expandSpacingShorthand' }],
256
254
  },
255
+ // Template literal containing expressions that is not token should only throw error with no autofix
256
+ {
257
+ name: `${property}: property value template string where it contains an expression that is not a token`,
258
+ code: outdent`
259
+ import {css} from '@compiled/react';
260
+ const styles = css({
261
+ ${property}: \`\${token('space.100', '8px')} \${gridSize * 2}px\`,
262
+ });
263
+ const styles2 = css({
264
+ padding: \`\${DROPDOWN_HEADER_VERTICAL_PADDING} \${token('space.075','6px')}
265
+ \${DROPDOWN_HEADER_VERTICAL_PADDING} \${token('space.200', '16px')}\`,
266
+ });
267
+ const styles3 = css({
268
+ ${property}: \`\${token('space.050', '4px')} \${token('space.150', '12px')} \${token('space.150', '12px')}
269
+ \${({ isSummaryView }: EditFormContentWrapperProps) =>
270
+ isSummaryView ? token('space.0', '0') : token('space.150', '12px')}\`,
271
+ });
272
+ `,
273
+ errors: Array.from(Array(3), () => ({ messageId: 'expandSpacingShorthand' })),
274
+ },
257
275
  // Miscellaneous
258
276
  {
259
277
  name: `${property}: new property should not be created if existing property already exists`,
@@ -329,16 +347,70 @@ const invalidTestCases = (property: string) => {
329
347
  `,
330
348
  errors: Array.from(Array(3), () => ({ messageId: 'expandSpacingShorthand' })),
331
349
  },
350
+ {
351
+ name: `${property}: property value includes newline and tab`,
352
+ code: outdent`
353
+ import {css} from '@compiled/react';
354
+ const styles = css({
355
+ ${property}: \`\${token('space.100')} \${token('space.200')}
356
+ \${token('space.300')} \${token('space.400')}\`,
357
+ });
358
+ const styles2 = css({
359
+ paddingBottom: token('space.050', '4px'),
360
+ '&& > span': {
361
+ padding: \`\${token('space.100', '8px')} \${token('space.150', '12px')} 7px
362
+ \${token('space.150', '12px')}\`,
363
+ },
364
+ });
365
+ `,
366
+ output: outdent`
367
+ import {css} from '@compiled/react';
368
+ const styles = css({
369
+ ${property}Top: token('space.100'),
370
+ ${property}Right: token('space.200'),
371
+ ${property}Bottom: token('space.300'),
372
+ ${property}Left: token('space.400'),
373
+ });
374
+ const styles2 = css({
375
+ paddingBottom: token('space.050', '4px'),
376
+ '&& > span': {
377
+ paddingTop: token('space.100', '8px'),
378
+ paddingRight: token('space.150', '12px'),
379
+ paddingBottom: '7px',
380
+ paddingLeft: token('space.150', '12px'),
381
+ },
382
+ });
383
+ `,
384
+ errors: Array.from(Array(2), () => ({ messageId: 'expandSpacingShorthand' })),
385
+ },
386
+ // TODO (AFB-1022): Resolve this failing test
387
+ // {
388
+ // name: `${property}: styled components with prop input`,
389
+ // code: outdent`
390
+ // import { styled } from '@compiled/react';
391
+ // const MenuOptionWrapper = styled.div<{ isDisabled: boolean }>({
392
+ // '& button': ({ isDisabled }) => ({
393
+ // ${property}: \`\${token('space.075', '6px')} \${token('space.200', '16px')}\`,
394
+ // }),
395
+ // });
396
+ // `,
397
+ // output: outdent`
398
+ // import { styled } from '@compiled/react';
399
+ // const MenuOptionWrapper = styled.div<{ isDisabled: boolean }>({
400
+ // '& button': ({ isDisabled }) => ({
401
+ // ${property}Top: token('space.075', '6px'),
402
+ // ${property}Right: token('space.200', '16px'),
403
+ // ${property}Bottom: token('space.075', '6px'),
404
+ // ${property}Left: token('space.200', '16px'),
405
+ // }),
406
+ // });
407
+ // `,
408
+ // errors: [{ messageId: 'expandSpacingShorthand' }],
409
+ // },
332
410
  ];
333
411
  };
334
412
 
335
413
  tester.run('expand-spacing-shorthand', expandSpacingShorthand, {
336
- valid: [
337
- ...validTestCases('padding'),
338
- ...validTestCases('margin'),
339
- ],
340
- invalid: [
341
- ...invalidTestCases('padding'),
342
- ...invalidTestCases('margin'),
343
- ],
414
+ valid: [...validTestCases('padding'), ...validTestCases('margin')],
415
+ invalid: [...invalidTestCases('padding'), ...invalidTestCases('margin')],
344
416
  });
@@ -3,15 +3,15 @@ import type { Property, Node, TemplateLiteral, CallExpression } from 'estree';
3
3
  import { getSourceCode } from '../../util/context-compat';
4
4
  import { isCompiledAPI } from '../../util/compiled-utils';
5
5
 
6
- const spacingPos = ["Top", "Right", "Bottom", "Left"] as const;
6
+ const spacingPos = ['Top', 'Right', 'Bottom', 'Left'] as const;
7
7
 
8
8
  interface ExpandSpacingPropertiesType {
9
- context: Rule.RuleContext,
10
- node: Property & { parent?: Node },
11
- propertyValues: string[],
12
- fixer: Rule.RuleFixer,
13
- propertyShorthand: string,
14
- };
9
+ context: Rule.RuleContext;
10
+ node: Property & { parent?: Node };
11
+ propertyValues: string[];
12
+ fixer: Rule.RuleFixer;
13
+ propertyShorthand: string;
14
+ }
15
15
 
16
16
  // Checks if node is a call expression with identifier 'token'
17
17
  const isTokenCallExpression = (node: CallExpression) => {
@@ -29,12 +29,15 @@ const parseTemplateLiteral = (templateLiteral: TemplateLiteral, context: Rule.Ru
29
29
 
30
30
  let propertyValues: string[] = [];
31
31
  for (let i = 0; i < expressions.length || i < quasis.length; i++) {
32
- if (i < quasis.length) {
32
+ if (i < quasis.length) {
33
33
  const cookedQuasi = quasis[i].value.cooked;
34
34
  if (cookedQuasi) {
35
- const splitQuasi = cookedQuasi.split(" ").filter(str => str.length > 0);
36
- splitQuasi.forEach(str => {
37
- propertyValues.push(isNaN(Number(str)) ? `'${str}'` : str);
35
+ const splitQuasis = cookedQuasi.split(' ');
36
+ splitQuasis.forEach((str) => {
37
+ str = str.trim().replace("\'", "");
38
+ if (str.length > 0) {
39
+ propertyValues.push(isNaN(Number(str)) ? `'${str}'` : str);
40
+ }
38
41
  });
39
42
  }
40
43
  }
@@ -47,14 +50,34 @@ const parseTemplateLiteral = (templateLiteral: TemplateLiteral, context: Rule.Ru
47
50
  };
48
51
 
49
52
  const checkValidPropertyValues = (propertyValues: string[]) => {
50
- if (!propertyValues.some(str => str.includes("token("))) { return false; }
51
- if (propertyValues.length < 1 || propertyValues.length > 4) { return false; }
52
- if (propertyValues.some(str => str.includes("calc("))) { return false; }
53
+ if (!propertyValues.some((str) => str.includes('token('))) {
54
+ return false;
55
+ }
56
+ if (propertyValues.length < 1 || propertyValues.length > 4) {
57
+ return false;
58
+ }
59
+ if (propertyValues.some((str) => str.includes('calc('))) {
60
+ return false;
61
+ }
53
62
  return true;
54
- }
63
+ };
64
+
65
+ // Check that all expressions in TemplateLiteral are token expressions
66
+ // If true: create an autofix
67
+ // If false: report violation without autofix
68
+ const hasOnlyTokens = (templateLiteral: TemplateLiteral) => {
69
+ const expressions = templateLiteral.expressions;
70
+ return expressions.every((expr) => expr.type === 'CallExpression' && isTokenCallExpression(expr));
71
+ };
55
72
 
56
73
  // To fix spacing shorthands, given a list of spacing property values, expands the spacing property and adds autofix fixes
57
- const expandSpacingProperties = ({ context, node, propertyValues, fixer, propertyShorthand }: ExpandSpacingPropertiesType) => {
74
+ const expandSpacingProperties = ({
75
+ context,
76
+ node,
77
+ propertyValues,
78
+ fixer,
79
+ propertyShorthand,
80
+ }: ExpandSpacingPropertiesType) => {
58
81
  const [top, right = top, bottom = top, left = right] = propertyValues;
59
82
  const spacing: string[] = [top, right, bottom, left];
60
83
 
@@ -63,16 +86,22 @@ const expandSpacingProperties = ({ context, node, propertyValues, fixer, propert
63
86
  const parentNode = node.parent;
64
87
  if (parentNode && parentNode.type === 'ObjectExpression') {
65
88
  for (var prop of parentNode.properties) {
66
- if (prop.type !== 'Property') { continue; }
67
- if (prop.key.type === 'Identifier' && prop.range && prop.key.name !== `${propertyShorthand}`) {
89
+ if (prop.type !== 'Property') {
90
+ continue;
91
+ }
92
+ if (
93
+ prop.key.type === 'Identifier' &&
94
+ prop.range &&
95
+ prop.key.name !== `${propertyShorthand}`
96
+ ) {
68
97
  for (let i = 0; i < spacing.length; i++) {
69
98
  if (prop.key.name === `${propertyShorthand}${spacingPos[i]}`) {
70
99
  let [start, end] = prop.range;
71
100
  // Remove the entire line for the duplicate property
72
- while (getSourceCode(context).text[end] !== "\n") {
101
+ while (getSourceCode(context).text[end] !== '\n') {
73
102
  end += 1;
74
103
  }
75
- while (getSourceCode(context).text[start] !== "\n") {
104
+ while (getSourceCode(context).text[start] !== '\n') {
76
105
  start -= 1;
77
106
  }
78
107
  spacing[i] = getSourceCode(context).getText(prop.value);
@@ -83,7 +112,7 @@ const expandSpacingProperties = ({ context, node, propertyValues, fixer, propert
83
112
  }
84
113
  }
85
114
  }
86
-
115
+
87
116
  fixes.push(fixer.insertTextAfter(node, `${propertyShorthand}Top: ${spacing[0]},\n`));
88
117
  fixes.push(fixer.insertTextAfter(node, `\t${propertyShorthand}Right: ${spacing[1]},\n`));
89
118
  fixes.push(fixer.insertTextAfter(node, `\t${propertyShorthand}Bottom: ${spacing[2]},\n`));
@@ -92,12 +121,30 @@ const expandSpacingProperties = ({ context, node, propertyValues, fixer, propert
92
121
  return fixes;
93
122
  };
94
123
 
95
- const executeExpandSpacingRule = (context: Rule.RuleContext, node: Property, propertyShorthand: string) => {
96
- if (!isCompiledAPI(context, node)) { return; }
124
+ const executeExpandSpacingRule = (
125
+ context: Rule.RuleContext,
126
+ node: Property,
127
+ propertyShorthand: string,
128
+ ) => {
129
+ if (!isCompiledAPI(context, node)) {
130
+ return;
131
+ }
97
132
  if (node.value.type === 'TemplateLiteral') {
98
133
  // Value of spacing property is a TemplateLiteral type that contains a token, e.g. padding: `0 token('a')`
134
+ if (!hasOnlyTokens(node.value)) {
135
+ context.report({
136
+ node,
137
+ messageId: 'expandSpacingShorthand',
138
+ data: {
139
+ property: propertyShorthand,
140
+ },
141
+ });
142
+ return;
143
+ }
99
144
  const propertyValues = parseTemplateLiteral(node.value, context);
100
- if (!checkValidPropertyValues(propertyValues)) { return; }
145
+ if (!checkValidPropertyValues(propertyValues)) {
146
+ return;
147
+ }
101
148
  context.report({
102
149
  node,
103
150
  messageId: 'expandSpacingShorthand',
@@ -105,12 +152,12 @@ const executeExpandSpacingRule = (context: Rule.RuleContext, node: Property, pro
105
152
  property: propertyShorthand,
106
153
  },
107
154
  fix(fixer) {
108
- return expandSpacingProperties({context, node, propertyValues, fixer, propertyShorthand});
155
+ return expandSpacingProperties({ context, node, propertyValues, fixer, propertyShorthand });
109
156
  },
110
157
  });
111
158
  } else if (node.value.type === 'CallExpression' && isTokenCallExpression(node.value)) {
112
159
  // Value of spacing property is a token CallExpression type, e.g. margin: token('space.100', '8px')
113
- const propertyValues = [ getSourceCode(context).getText(node.value) ];
160
+ const propertyValues = [getSourceCode(context).getText(node.value)];
114
161
  context.report({
115
162
  node,
116
163
  messageId: 'expandSpacingShorthand',
@@ -118,11 +165,11 @@ const executeExpandSpacingRule = (context: Rule.RuleContext, node: Property, pro
118
165
  property: propertyShorthand,
119
166
  },
120
167
  fix(fixer) {
121
- return expandSpacingProperties({context, node, propertyValues, fixer, propertyShorthand});
168
+ return expandSpacingProperties({ context, node, propertyValues, fixer, propertyShorthand });
122
169
  },
123
170
  });
124
171
  }
125
- }
172
+ };
126
173
 
127
174
  export const expandSpacingShorthand: Rule.RuleModule = {
128
175
  meta: {
@@ -130,7 +177,8 @@ export const expandSpacingShorthand: Rule.RuleModule = {
130
177
  url: 'https://bitbucket.org/atlassian/atlassian-frontend-monorepo/src/master/platform/packages/platform/eslint-plugin/src/rules/compiled/expand-spacing-shorthand/',
131
178
  },
132
179
  messages: {
133
- expandSpacingShorthand: 'Use {{ property }}Top, {{ property }}Right, {{ property }}Bottom and {{ property }}Left instead of {{ property }} shorthand',
180
+ expandSpacingShorthand:
181
+ 'Use {{ property }}Top, {{ property }}Right, {{ property }}Bottom and {{ property }}Left instead of {{ property }} shorthand',
134
182
  },
135
183
  type: 'problem',
136
184
  fixable: 'code',
@@ -147,4 +195,4 @@ export const expandSpacingShorthand: Rule.RuleModule = {
147
195
  },
148
196
  };
149
197
 
150
- export default expandSpacingShorthand;
198
+ export default expandSpacingShorthand;