@atlaskit/eslint-plugin-design-system 8.37.3 → 9.0.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.
Files changed (78) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +1 -0
  3. package/constellation/consistent-css-prop-usage/usage.mdx +3 -19
  4. package/constellation/index/usage.mdx +1 -0
  5. package/constellation/use-tokens-space/usage.mdx +30 -0
  6. package/dist/cjs/ast-nodes/object-entry.js +35 -0
  7. package/dist/cjs/ast-nodes/object.js +12 -0
  8. package/dist/cjs/presets/all.codegen.js +2 -1
  9. package/dist/cjs/rules/consistent-css-prop-usage/index.js +53 -85
  10. package/dist/cjs/rules/index.codegen.js +3 -1
  11. package/dist/cjs/rules/use-tokens-space/index.js +54 -0
  12. package/dist/cjs/rules/use-tokens-space/transformers/index.js +12 -0
  13. package/dist/cjs/rules/use-tokens-space/transformers/style-property/index.js +130 -0
  14. package/dist/cjs/rules/use-tokens-space/transformers/style-property/style-map.js +80 -0
  15. package/dist/cjs/rules/use-tokens-space/transformers/style-property/supported.js +14 -0
  16. package/dist/cjs/rules/use-tokens-space/transformers/style-property/upsert-import-declaration.js +37 -0
  17. package/dist/cjs/rules/use-tokens-space/utils/index.js +12 -0
  18. package/dist/cjs/rules/use-tokens-space/utils/is-string-or-number.js +9 -0
  19. package/dist/cjs/rules/utils/is-supported-import.js +12 -3
  20. package/dist/es2019/ast-nodes/object-entry.js +37 -3
  21. package/dist/es2019/ast-nodes/object.js +12 -0
  22. package/dist/es2019/presets/all.codegen.js +2 -1
  23. package/dist/es2019/rules/consistent-css-prop-usage/index.js +21 -48
  24. package/dist/es2019/rules/index.codegen.js +3 -1
  25. package/dist/es2019/rules/use-tokens-space/index.js +38 -0
  26. package/dist/es2019/rules/use-tokens-space/transformers/index.js +1 -0
  27. package/dist/es2019/rules/use-tokens-space/transformers/style-property/index.js +121 -0
  28. package/dist/es2019/rules/use-tokens-space/transformers/style-property/style-map.js +152 -0
  29. package/dist/es2019/rules/use-tokens-space/transformers/style-property/supported.js +8 -0
  30. package/dist/es2019/rules/use-tokens-space/transformers/style-property/upsert-import-declaration.js +30 -0
  31. package/dist/es2019/rules/use-tokens-space/utils/index.js +1 -0
  32. package/dist/es2019/rules/use-tokens-space/utils/is-string-or-number.js +3 -0
  33. package/dist/es2019/rules/utils/is-supported-import.js +15 -2
  34. package/dist/esm/ast-nodes/object-entry.js +37 -3
  35. package/dist/esm/ast-nodes/object.js +12 -0
  36. package/dist/esm/presets/all.codegen.js +2 -1
  37. package/dist/esm/rules/consistent-css-prop-usage/index.js +53 -85
  38. package/dist/esm/rules/index.codegen.js +3 -1
  39. package/dist/esm/rules/use-tokens-space/index.js +48 -0
  40. package/dist/esm/rules/use-tokens-space/transformers/index.js +1 -0
  41. package/dist/esm/rules/use-tokens-space/transformers/style-property/index.js +120 -0
  42. package/dist/esm/rules/use-tokens-space/transformers/style-property/style-map.js +73 -0
  43. package/dist/esm/rules/use-tokens-space/transformers/style-property/supported.js +8 -0
  44. package/dist/esm/rules/use-tokens-space/transformers/style-property/upsert-import-declaration.js +29 -0
  45. package/dist/esm/rules/use-tokens-space/utils/index.js +1 -0
  46. package/dist/esm/rules/use-tokens-space/utils/is-string-or-number.js +3 -0
  47. package/dist/esm/rules/utils/is-supported-import.js +11 -2
  48. package/dist/types/ast-nodes/object-entry.d.ts +12 -2
  49. package/dist/types/ast-nodes/object.d.ts +1 -0
  50. package/dist/types/index.codegen.d.ts +1 -0
  51. package/dist/types/presets/all.codegen.d.ts +2 -1
  52. package/dist/types/rules/consistent-css-prop-usage/types.d.ts +1 -2
  53. package/dist/types/rules/index.codegen.d.ts +1 -0
  54. package/dist/types/rules/use-tokens-space/index.d.ts +3 -0
  55. package/dist/types/rules/use-tokens-space/transformers/index.d.ts +1 -0
  56. package/dist/types/rules/use-tokens-space/transformers/style-property/index.d.ts +26 -0
  57. package/dist/types/rules/use-tokens-space/transformers/style-property/style-map.d.ts +7 -0
  58. package/dist/types/rules/use-tokens-space/transformers/style-property/supported.d.ts +6 -0
  59. package/dist/types/rules/use-tokens-space/transformers/style-property/upsert-import-declaration.d.ts +14 -0
  60. package/dist/types/rules/use-tokens-space/utils/index.d.ts +1 -0
  61. package/dist/types/rules/use-tokens-space/utils/is-string-or-number.d.ts +1 -0
  62. package/dist/types/rules/utils/is-supported-import.d.ts +5 -4
  63. package/dist/types-ts4.5/ast-nodes/object-entry.d.ts +12 -2
  64. package/dist/types-ts4.5/ast-nodes/object.d.ts +1 -0
  65. package/dist/types-ts4.5/index.codegen.d.ts +1 -0
  66. package/dist/types-ts4.5/presets/all.codegen.d.ts +2 -1
  67. package/dist/types-ts4.5/rules/consistent-css-prop-usage/types.d.ts +1 -2
  68. package/dist/types-ts4.5/rules/index.codegen.d.ts +1 -0
  69. package/dist/types-ts4.5/rules/use-tokens-space/index.d.ts +3 -0
  70. package/dist/types-ts4.5/rules/use-tokens-space/transformers/index.d.ts +1 -0
  71. package/dist/types-ts4.5/rules/use-tokens-space/transformers/style-property/index.d.ts +26 -0
  72. package/dist/types-ts4.5/rules/use-tokens-space/transformers/style-property/style-map.d.ts +7 -0
  73. package/dist/types-ts4.5/rules/use-tokens-space/transformers/style-property/supported.d.ts +6 -0
  74. package/dist/types-ts4.5/rules/use-tokens-space/transformers/style-property/upsert-import-declaration.d.ts +14 -0
  75. package/dist/types-ts4.5/rules/use-tokens-space/utils/index.d.ts +1 -0
  76. package/dist/types-ts4.5/rules/use-tokens-space/utils/is-string-or-number.d.ts +1 -0
  77. package/dist/types-ts4.5/rules/utils/is-supported-import.d.ts +5 -4
  78. package/package.json +2 -2
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.styleMap = void 0;
8
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
9
+ var _tokenMap;
10
+ // TODO: https://product-fabric.atlassian.net/browse/DSP-16054
11
+ var tokenMap = (_tokenMap = {
12
+ '-2px': 'space.negative.025',
13
+ '-4px': 'space.negative.050',
14
+ '-6px': 'space.negative.075',
15
+ '-8px': 'space.negative.100',
16
+ '-12px': 'space.negative.150',
17
+ '-16px': 'space.negative.200',
18
+ '-20px': 'space.negative.250',
19
+ '-24px': 'space.negative.300',
20
+ '-32px': 'space.negative.400'
21
+ }, (0, _defineProperty2.default)(_tokenMap, -2, 'space.negative.025'), (0, _defineProperty2.default)(_tokenMap, -4, 'space.negative.050'), (0, _defineProperty2.default)(_tokenMap, -6, 'space.negative.075'), (0, _defineProperty2.default)(_tokenMap, -8, 'space.negative.100'), (0, _defineProperty2.default)(_tokenMap, -12, 'space.negative.150'), (0, _defineProperty2.default)(_tokenMap, -16, 'space.negative.200'), (0, _defineProperty2.default)(_tokenMap, -20, 'space.negative.250'), (0, _defineProperty2.default)(_tokenMap, -24, 'space.negative.300'), (0, _defineProperty2.default)(_tokenMap, -32, 'space.negative.400'), (0, _defineProperty2.default)(_tokenMap, '2px', 'space.025'), (0, _defineProperty2.default)(_tokenMap, '4px', 'space.050'), (0, _defineProperty2.default)(_tokenMap, '6px', 'space.075'), (0, _defineProperty2.default)(_tokenMap, '8px', 'space.100'), (0, _defineProperty2.default)(_tokenMap, '12px', 'space.150'), (0, _defineProperty2.default)(_tokenMap, '16px', 'space.200'), (0, _defineProperty2.default)(_tokenMap, '20px', 'space.250'), (0, _defineProperty2.default)(_tokenMap, '24px', 'space.300'), (0, _defineProperty2.default)(_tokenMap, '32px', 'space.400'), (0, _defineProperty2.default)(_tokenMap, '40px', 'space.500'), (0, _defineProperty2.default)(_tokenMap, '48px', 'space.600'), (0, _defineProperty2.default)(_tokenMap, '64px', 'space.800'), (0, _defineProperty2.default)(_tokenMap, '80px', 'space.1000'), (0, _defineProperty2.default)(_tokenMap, 2, 'space.025'), (0, _defineProperty2.default)(_tokenMap, 4, 'space.050'), (0, _defineProperty2.default)(_tokenMap, 6, 'space.075'), (0, _defineProperty2.default)(_tokenMap, 8, 'space.100'), (0, _defineProperty2.default)(_tokenMap, 12, 'space.150'), (0, _defineProperty2.default)(_tokenMap, 16, 'space.200'), (0, _defineProperty2.default)(_tokenMap, 20, 'space.250'), (0, _defineProperty2.default)(_tokenMap, 24, 'space.300'), (0, _defineProperty2.default)(_tokenMap, 32, 'space.400'), (0, _defineProperty2.default)(_tokenMap, 40, 'space.500'), (0, _defineProperty2.default)(_tokenMap, 48, 'space.600'), (0, _defineProperty2.default)(_tokenMap, 64, 'space.800'), (0, _defineProperty2.default)(_tokenMap, 80, 'space.1000'), (0, _defineProperty2.default)(_tokenMap, '-0.125rem', 'space.negative.025'), (0, _defineProperty2.default)(_tokenMap, '-0.25rem', 'space.negative.050'), (0, _defineProperty2.default)(_tokenMap, '-0.375rem', 'space.negative.075'), (0, _defineProperty2.default)(_tokenMap, '-0.5rem', 'space.negative.100'), (0, _defineProperty2.default)(_tokenMap, '-0.75rem', 'space.negative.150'), (0, _defineProperty2.default)(_tokenMap, '-1rem', 'space.negative.200'), (0, _defineProperty2.default)(_tokenMap, '-1.25rem', 'space.negative.250'), (0, _defineProperty2.default)(_tokenMap, '-1.5rem', 'space.negative.300'), (0, _defineProperty2.default)(_tokenMap, '-2rem', 'space.negative.400'), (0, _defineProperty2.default)(_tokenMap, '0.125rem', 'space.025'), (0, _defineProperty2.default)(_tokenMap, '0.25rem', 'space.050'), (0, _defineProperty2.default)(_tokenMap, '0.375rem', 'space.075'), (0, _defineProperty2.default)(_tokenMap, '0.5rem', 'space.100'), (0, _defineProperty2.default)(_tokenMap, '0.75rem', 'space.150'), (0, _defineProperty2.default)(_tokenMap, '1rem', 'space.200'), (0, _defineProperty2.default)(_tokenMap, '1.25rem', 'space.250'), (0, _defineProperty2.default)(_tokenMap, '1.5rem', 'space.300'), (0, _defineProperty2.default)(_tokenMap, '2rem', 'space.400'), (0, _defineProperty2.default)(_tokenMap, '2.5rem', 'space.500'), (0, _defineProperty2.default)(_tokenMap, '3rem', 'space.600'), (0, _defineProperty2.default)(_tokenMap, '4rem', 'space.800'), (0, _defineProperty2.default)(_tokenMap, '5rem', 'space.1000'), (0, _defineProperty2.default)(_tokenMap, '-0.125em', 'space.negative.025'), (0, _defineProperty2.default)(_tokenMap, '-0.25em', 'space.negative.050'), (0, _defineProperty2.default)(_tokenMap, '-0.375em', 'space.negative.075'), (0, _defineProperty2.default)(_tokenMap, '-0.5em', 'space.negative.100'), (0, _defineProperty2.default)(_tokenMap, '-0.75em', 'space.negative.150'), (0, _defineProperty2.default)(_tokenMap, '-1em', 'space.negative.200'), (0, _defineProperty2.default)(_tokenMap, '-1.25em', 'space.negative.250'), (0, _defineProperty2.default)(_tokenMap, '-1.5em', 'space.negative.300'), (0, _defineProperty2.default)(_tokenMap, '-2em', 'space.negative.400'), (0, _defineProperty2.default)(_tokenMap, '0.125em', 'space.025'), (0, _defineProperty2.default)(_tokenMap, '0.25em', 'space.050'), (0, _defineProperty2.default)(_tokenMap, '0.375em', 'space.075'), (0, _defineProperty2.default)(_tokenMap, '0.5em', 'space.100'), (0, _defineProperty2.default)(_tokenMap, '0.75em', 'space.150'), (0, _defineProperty2.default)(_tokenMap, '1em', 'space.200'), (0, _defineProperty2.default)(_tokenMap, '1.25em', 'space.250'), (0, _defineProperty2.default)(_tokenMap, '1.5em', 'space.300'), (0, _defineProperty2.default)(_tokenMap, '2em', 'space.400'), (0, _defineProperty2.default)(_tokenMap, '2.5em', 'space.500'), (0, _defineProperty2.default)(_tokenMap, '3em', 'space.600'), (0, _defineProperty2.default)(_tokenMap, '4em', 'space.800'), (0, _defineProperty2.default)(_tokenMap, '5em', 'space.1000'), _tokenMap);
22
+ var styleMap = exports.styleMap = {
23
+ 'column-gap': tokenMap,
24
+ columnGap: tokenMap,
25
+ gap: tokenMap,
26
+ 'grid-column-gap': tokenMap,
27
+ 'grid-row-gap': tokenMap,
28
+ gridColumnGap: tokenMap,
29
+ gridRowGap: tokenMap,
30
+ 'margin-block-end': tokenMap,
31
+ 'margin-block-start': tokenMap,
32
+ 'margin-block': tokenMap,
33
+ 'margin-bottom': tokenMap,
34
+ 'margin-inline-end': tokenMap,
35
+ 'margin-inline-start': tokenMap,
36
+ 'margin-inline': tokenMap,
37
+ 'margin-left': tokenMap,
38
+ 'margin-right': tokenMap,
39
+ 'margin-top': tokenMap,
40
+ 'outline-offset': tokenMap,
41
+ outlineOffset: tokenMap,
42
+ 'padding-block-end': tokenMap,
43
+ 'padding-block-start': tokenMap,
44
+ 'padding-block': tokenMap,
45
+ 'padding-bottom': tokenMap,
46
+ 'padding-inline-end': tokenMap,
47
+ 'padding-inline-start': tokenMap,
48
+ 'padding-inline': tokenMap,
49
+ 'padding-left': tokenMap,
50
+ 'padding-right': tokenMap,
51
+ 'padding-top': tokenMap,
52
+ 'row-gap': tokenMap,
53
+ rowGap: tokenMap,
54
+ margin: tokenMap,
55
+ marginBlock: tokenMap,
56
+ marginBlockEnd: tokenMap,
57
+ marginBlockStart: tokenMap,
58
+ marginBottom: tokenMap,
59
+ marginInline: tokenMap,
60
+ marginInlineEnd: tokenMap,
61
+ marginInlineStart: tokenMap,
62
+ marginLeft: tokenMap,
63
+ marginRight: tokenMap,
64
+ marginTop: tokenMap,
65
+ padding: tokenMap,
66
+ paddingBlock: tokenMap,
67
+ paddingBlockEnd: tokenMap,
68
+ paddingBlockStart: tokenMap,
69
+ paddingBottom: tokenMap,
70
+ paddingInline: tokenMap,
71
+ paddingInlineEnd: tokenMap,
72
+ paddingInlineStart: tokenMap,
73
+ paddingLeft: tokenMap,
74
+ paddingRight: tokenMap,
75
+ paddingTop: tokenMap
76
+ // bottom: tokenMap,
77
+ // left: tokenMap,
78
+ // right: tokenMap,
79
+ // top: tokenMap,
80
+ };
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _default = exports.default = {
8
+ values: {
9
+ ignore: ['auto', 'initial', 'inherit', 'unset', 'revert', 'revert-layer', 'none',
10
+ // outline-offset can be set to none
11
+ // Currently the DST opinion is that 0 is valid. It doesn't need to be converted to `space.0`
12
+ 0, '0', '0px', '0em', '0rem']
13
+ }
14
+ };
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+
3
+ var _typeof = require("@babel/runtime/helpers/typeof");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.upsertImportDeclaration = void 0;
8
+ var ast = _interopRequireWildcard(require("../../../../ast-nodes"));
9
+ function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
10
+ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof(e) && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
11
+ /**
12
+ * Currently this is defined here because it's not very general purpose.
13
+ * If we were to move this to `ast-nodes`, half the implementation would be in `Root`,
14
+ * and the other half would be in `Import`.
15
+ *
16
+ * TODO: Refactor and move to `ast-nodes`
17
+ *
18
+ * Note: It does not handle default imports, namespace imports, or aliased imports.
19
+ */
20
+ var upsertImportDeclaration = exports.upsertImportDeclaration = function upsertImportDeclaration(_ref, context, fixer) {
21
+ var module = _ref.module,
22
+ specifiers = _ref.specifiers;
23
+ // Find any imports that match the packageName
24
+ var root = context.getSourceCode().ast.body;
25
+ var importDeclarations = ast.Root.findImportsByModule(root, module);
26
+
27
+ // The import doesn't exist yet, we can just insert a whole new one
28
+ if (importDeclarations.length === 0) {
29
+ return ast.Root.insertImport(root, {
30
+ module: module,
31
+ specifiers: specifiers
32
+ }, fixer);
33
+ }
34
+
35
+ // The import exists so, modify the existing one
36
+ return ast.Import.insertNamedSpecifiers(importDeclarations[0], specifiers, fixer);
37
+ };
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ Object.defineProperty(exports, "isStringOrNumber", {
7
+ enumerable: true,
8
+ get: function get() {
9
+ return _isStringOrNumber.isStringOrNumber;
10
+ }
11
+ });
12
+ var _isStringOrNumber = require("./is-string-or-number");
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.isStringOrNumber = void 0;
7
+ var isStringOrNumber = exports.isStringOrNumber = function isStringOrNumber(value) {
8
+ return typeof value === 'string' || typeof value === 'number';
9
+ };
@@ -3,7 +3,14 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.isStyledComponents = exports.isStyled = exports.isKeyframes = exports.isImportedFrom = exports.isEmotion = exports.isCxFunction = exports.isCssMap = exports.isCss = exports.isCompiled = exports.getImportSources = exports.DEFAULT_IMPORT_SOURCES = exports.CSS_IN_JS_IMPORTS = void 0;
6
+ exports.isXcss = exports.isStyledComponents = exports.isStyled = exports.isKeyframes = exports.isImportedFrom = exports.isEmotion = exports.isCxFunction = exports.isCssMap = exports.isCss = exports.isCompiled = exports.getImportSources = exports.DEFAULT_IMPORT_SOURCES = exports.CSS_IN_JS_IMPORTS = void 0;
7
+ // This should be kept in sync with
8
+ // packages/design-system/eslint-plugin-ui-styling-standard/src/rules/utils/is-supported-import.tsx
9
+ // whenever possible.
10
+ //
11
+ // TODO: would having an @atlassian/eslint-plugin-design-system-common
12
+ // package be useful?
13
+
7
14
  // eslint-disable-next-line import/no-extraneous-dependencies
8
15
 
9
16
  var CSS_IN_JS_IMPORTS = exports.CSS_IN_JS_IMPORTS = {
@@ -118,10 +125,12 @@ var isCssMap = exports.isCssMap = isSupportedImportWrapper('cssMap');
118
125
  var isKeyframes = exports.isKeyframes = isSupportedImportWrapper('keyframes');
119
126
  // `styled` is also the explicit default of `styled-components` and `@emotion/styled`, so we also match on default imports generally
120
127
  var isStyled = exports.isStyled = isSupportedImportWrapper('styled', ['styled-components', '@emotion/styled']);
128
+ var isXcss = exports.isXcss = isSupportedImportWrapper('xcss');
121
129
  var isImportedFrom = exports.isImportedFrom = function isImportedFrom(moduleName) {
122
130
  var exactMatch = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
123
- return function (nodeToCheck, referencesInScope, importSources) {
124
- if (!importSources.some(function (importSource) {
131
+ return function (nodeToCheck, referencesInScope) {
132
+ var importSources = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
133
+ if (importSources && !importSources.some(function (importSource) {
125
134
  return importSource === moduleName || !exactMatch && importSource.startsWith(moduleName);
126
135
  })) {
127
136
  // Don't go through the trouble of checking the import sources does not include this
@@ -1,5 +1,40 @@
1
+ /* eslint-disable @repo/internal/react/require-jsdoc */
2
+
1
3
  import { isNodeOfType } from 'eslint-codemod-utils';
2
- const ObjectEntry = {
4
+ export const ObjectEntry = {
5
+ getProperty(node) {
6
+ if (isNodeOfType(node.key, 'Identifier')) {
7
+ return {
8
+ type: 'Identifier',
9
+ value: node.key.name
10
+ };
11
+ }
12
+ if (isNodeOfType(node.key, 'Literal') && node.key.value) {
13
+ return {
14
+ type: 'Literal',
15
+ value: node.key.value.toString()
16
+ };
17
+ }
18
+ return {
19
+ type: undefined,
20
+ value: undefined
21
+ };
22
+ },
23
+ getValue(node) {
24
+ // The value is a number, like `-3`
25
+ if (isNodeOfType(node.value, 'UnaryExpression') && isNodeOfType(node.value.argument, 'Literal') && node.value.argument.raw) {
26
+ if (node.value.operator === '-') {
27
+ return -1 * Number.parseInt(node.value.argument.raw);
28
+ }
29
+ return Number.parseInt(node.value.argument.raw);
30
+ }
31
+
32
+ // The value is a string, like `'4px'`
33
+ if (isNodeOfType(node.value, 'Literal') && node.value.value) {
34
+ return node.value.value;
35
+ }
36
+ return undefined;
37
+ },
3
38
  deleteEntry(node, context, fixer) {
4
39
  var _lastToken;
5
40
  // context.getSourceCode() is deprecated in favour of context.sourceCode, however this returns undefined for some reason
@@ -31,5 +66,4 @@ const ObjectEntry = {
31
66
  return node.key.name;
32
67
  }
33
68
  }
34
- };
35
- export { ObjectEntry };
69
+ };
@@ -99,6 +99,18 @@ const ASTObjectExpression = {
99
99
  key: identifier(key),
100
100
  value: literal(value)
101
101
  }).toString()}, `);
102
+ },
103
+ recurse(node, callback) {
104
+ node.properties.forEach(entry => {
105
+ // Call the callback first, in case the user wants to do something with SpreadElements
106
+ callback(entry);
107
+ if (!isNodeOfType(entry, 'Property')) {
108
+ return;
109
+ }
110
+ if (isNodeOfType(entry.value, 'ObjectExpression')) {
111
+ ASTObjectExpression.recurse(entry.value, callback);
112
+ }
113
+ });
102
114
  }
103
115
  };
104
116
  export { ASTObjectExpression as Object };
@@ -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::d90c2cf5e100daf98915f9467f2e5663>>
3
+ * @codegen <<SignedSource::d95217b658f807294de3c81123068bf1>>
4
4
  * @codegenCommand yarn workspace @atlaskit/eslint-plugin-design-system codegen
5
5
  */
6
6
  export default {
@@ -35,6 +35,7 @@ export default {
35
35
  '@atlaskit/design-system/use-href-in-link-item': 'warn',
36
36
  '@atlaskit/design-system/use-primitives': 'warn',
37
37
  '@atlaskit/design-system/use-primitives-text': 'warn',
38
+ '@atlaskit/design-system/use-tokens-space': 'error',
38
39
  '@atlaskit/design-system/use-tokens-typography': 'warn',
39
40
  '@atlaskit/design-system/use-visually-hidden': 'error'
40
41
  }
@@ -24,6 +24,18 @@ const getProgramNode = expression => {
24
24
  }
25
25
  return expression.parent;
26
26
  };
27
+ const isDeclaredInsideComponent = expression => {
28
+ // These nodes imply that there is a distinct own scope (function scope / block scope),
29
+ // and so the presence of them means that expression was not defined in the module scope.
30
+ const NOT_MODULE_SCOPE = ['ArrowFunctionExpression', 'BlockStatement', 'ClassDeclaration', 'FunctionExpression'];
31
+ while (expression.type !== 'Program') {
32
+ if (NOT_MODULE_SCOPE.includes(expression.type)) {
33
+ return true;
34
+ }
35
+ expression = expression.parent;
36
+ }
37
+ return false;
38
+ };
27
39
  class JSXExpressionLinter {
28
40
  // File-level tracking of styles hoisted from the cssAtTopOfModule/cssAtBottomOfModule fixers.
29
41
 
@@ -92,13 +104,13 @@ class JSXExpressionLinter {
92
104
  });
93
105
  return;
94
106
  }
95
- if (identifier.parent.parent.parent.type !== 'Program') {
107
+ if (isDeclaredInsideComponent(identifier)) {
96
108
  // When variable is declared inside the component
97
109
  this.context.report({
98
110
  node: sourceIdentifier,
99
111
  messageId: this.configuration.stylesPlacement === 'bottom' ? 'cssAtBottomOfModule' : 'cssAtTopOfModule',
100
112
  fix: fixer => {
101
- if (this.configuration.fixNamesOnly) {
113
+ if (!this.configuration.autoFix) {
102
114
  return [];
103
115
  }
104
116
  return this.fixCssNotInModuleScope(fixer, identifier, false);
@@ -120,7 +132,7 @@ class JSXExpressionLinter {
120
132
  node: identifier,
121
133
  messageId: 'cssObjectTypeOnly',
122
134
  fix: fixer => {
123
- if (this.configuration.fixNamesOnly) {
135
+ if (!this.configuration.autoFix) {
124
136
  return [];
125
137
  }
126
138
  return this.addCssFunctionCall(fixer, identifier.parent);
@@ -285,8 +297,9 @@ class JSXExpressionLinter {
285
297
  // The last value is the bottom of the file
286
298
  fixerNodePlacement = programNode.body[programNode.body.length - 1];
287
299
  } else {
300
+ var _ref;
288
301
  // Place after the last ImportDeclaration
289
- fixerNodePlacement = programNode.body.length === 1 ? programNode.body[0] : programNode.body.find(node => node.type !== 'ImportDeclaration');
302
+ fixerNodePlacement = (_ref = programNode.body.length === 1 ? programNode.body[0] : programNode.body.find(node => node.type !== 'ImportDeclaration')) !== null && _ref !== void 0 ? _ref : fixerNodePlacement;
290
303
  }
291
304
  let moduleString;
292
305
  let fixes = [];
@@ -363,7 +376,7 @@ class JSXExpressionLinter {
363
376
  node: expression,
364
377
  messageId: this.configuration.stylesPlacement === 'bottom' ? 'cssAtBottomOfModule' : 'cssAtTopOfModule',
365
378
  fix: fixer => {
366
- if (this.configuration.fixNamesOnly) {
379
+ if (!this.configuration.autoFix) {
367
380
  return [];
368
381
  }
369
382
 
@@ -404,8 +417,7 @@ const defaultConfig = {
404
417
  cssImportSource: CSS_IN_JS_IMPORTS.compiled,
405
418
  xcssImportSource: CSS_IN_JS_IMPORTS.atlaskitPrimitives,
406
419
  excludeReactComponents: false,
407
- fixNamesOnly: false,
408
- autoFixNames: true
420
+ autoFix: true
409
421
  };
410
422
  const rule = createLintRule({
411
423
  meta: {
@@ -424,8 +436,7 @@ const rule = createLintRule({
424
436
  cssObjectTypeOnly: `Create styles using objects passed to a css function call, e.g. \`css({ textAlign: 'center'; })\`.`,
425
437
  cssInModule: `Imported styles should not be used; instead define in the module, import a component, or use a design token.`,
426
438
  cssArrayStylesOnly: `Compose styles with an array on the css prop instead of using object spread.`,
427
- noMemberExpressions: `Styles should be a regular variable (e.g. 'buttonStyles'), not a member of an object (e.g. 'myObject.styles').`,
428
- shouldEndInStyles: 'Declared styles should end in "styles".'
439
+ noMemberExpressions: `Styles should be a regular variable (e.g. 'buttonStyles'), not a member of an object (e.g. 'myObject.styles').`
429
440
  },
430
441
  schema: [{
431
442
  type: 'object',
@@ -449,10 +460,7 @@ const rule = createLintRule({
449
460
  excludeReactComponents: {
450
461
  type: 'boolean'
451
462
  },
452
- autoFixNames: {
453
- type: 'boolean'
454
- },
455
- fixNamesOnly: {
463
+ autoFix: {
456
464
  type: 'boolean'
457
465
  }
458
466
  },
@@ -461,42 +469,7 @@ const rule = createLintRule({
461
469
  },
462
470
  create(context) {
463
471
  const mergedConfig = assign({}, defaultConfig, context.options[0]);
464
- const declarationSuffix = 'Styles';
465
- const callSelectorFunctions = [...mergedConfig.cssFunctions, 'cssMap'];
466
- const callSelector = callSelectorFunctions.map(fn => `CallExpression[callee.name=${fn}]`).join(',');
467
472
  return {
468
- [callSelector]: node => {
469
- if (node.parent.type !== 'VariableDeclarator') {
470
- // We aren't interested in these that don't have a parent.
471
- return;
472
- }
473
- const identifier = node.parent.id;
474
- if (identifier.type === 'Identifier' && (identifier.name.endsWith(declarationSuffix) || identifier.name.startsWith(declarationSuffix.toLowerCase()) || identifier.name === declarationSuffix.toLowerCase())) {
475
- // Already prefixed! Nothing to do.
476
- return;
477
- }
478
- if (!mergedConfig.autoFixNames) {
479
- return;
480
- }
481
- context.report({
482
- node: identifier,
483
- messageId: 'shouldEndInStyles',
484
- fix: fixer => {
485
- var _context$getScope$var;
486
- const identifierName = identifier.type === 'Identifier' ? identifier.name : '';
487
- const references = ((_context$getScope$var = context.getScope().variables.find(varb => varb.name === identifierName)) === null || _context$getScope$var === void 0 ? void 0 : _context$getScope$var.references) || [];
488
- const newIdentifierName = `${identifierName
489
- // Remove "Style" if it is already defined.
490
- .replace(/Style$/, '')}${declarationSuffix}`;
491
- return references.filter(ref => ref.identifier.name === identifierName).map(ref => {
492
- if (ref.identifier.parent && ref.identifier.parent.shorthand) {
493
- return fixer.replaceText(ref.identifier, `${identifierName}: ${newIdentifierName}`);
494
- }
495
- return fixer.replaceText(ref.identifier, newIdentifierName);
496
- });
497
- }
498
- });
499
- },
500
473
  JSXAttribute(nodeOriginal) {
501
474
  const node = nodeOriginal;
502
475
  const {
@@ -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::c283cd7ede5e813a9119cd707d339273>>
3
+ * @codegen <<SignedSource::d1c25758089a050334359276ede0ca3a>>
4
4
  * @codegenCommand yarn workspace @atlaskit/eslint-plugin-design-system codegen
5
5
  */
6
6
  import consistentCssPropUsage from './consistent-css-prop-usage';
@@ -32,6 +32,7 @@ import useHeadingLevelInSpotlightCard from './use-heading-level-in-spotlight-car
32
32
  import useHrefInLinkItem from './use-href-in-link-item';
33
33
  import usePrimitives from './use-primitives';
34
34
  import usePrimitivesText from './use-primitives-text';
35
+ import useTokensSpace from './use-tokens-space';
35
36
  import useTokensTypography from './use-tokens-typography';
36
37
  import useVisuallyHidden from './use-visually-hidden';
37
38
  export default {
@@ -64,6 +65,7 @@ export default {
64
65
  'use-href-in-link-item': useHrefInLinkItem,
65
66
  'use-primitives': usePrimitives,
66
67
  'use-primitives-text': usePrimitivesText,
68
+ 'use-tokens-space': useTokensSpace,
67
69
  'use-tokens-typography': useTokensTypography,
68
70
  'use-visually-hidden': useVisuallyHidden
69
71
  };
@@ -0,0 +1,38 @@
1
+ import { createLintRule } from '../utils/create-rule';
2
+ import { StyleProperty } from './transformers';
3
+ const rule = createLintRule({
4
+ meta: {
5
+ name: 'use-tokens-space',
6
+ type: 'problem',
7
+ fixable: 'code',
8
+ hasSuggestions: true,
9
+ docs: {
10
+ description: 'Enforces usage of space design tokens rather than hard-coded values.',
11
+ recommended: false,
12
+ severity: 'error'
13
+ },
14
+ messages: {
15
+ noRawSpacingValues: 'The use of spacing primitives or tokens is preferred over the direct application of spacing properties.'
16
+ }
17
+ },
18
+ create(context) {
19
+ return {
20
+ 'CallExpression[callee.name="css"] ObjectExpression Property': node => StyleProperty.lint(node, {
21
+ context
22
+ }),
23
+ 'CallExpression[callee.name="keyframes"] ObjectExpression Property': node => StyleProperty.lint(node, {
24
+ context
25
+ }),
26
+ 'CallExpression[callee.name="cssMap"] ObjectExpression Property': node => StyleProperty.lint(node, {
27
+ context
28
+ }),
29
+ 'CallExpression[callee.object.name=styled] ObjectExpression Property': node => StyleProperty.lint(node, {
30
+ context
31
+ }),
32
+ 'CallExpression[callee.object.name=styled2] ObjectExpression Property': node => StyleProperty.lint(node, {
33
+ context
34
+ })
35
+ };
36
+ }
37
+ });
38
+ export default rule;
@@ -0,0 +1 @@
1
+ export { StyleProperty } from './style-property';
@@ -0,0 +1,121 @@
1
+ /* eslint-disable @repo/internal/react/require-jsdoc */
2
+
3
+ import { isNodeOfType } from 'eslint-codemod-utils';
4
+ import * as ast from '../../../../ast-nodes';
5
+ import { isStringOrNumber } from '../../utils';
6
+ import { styleMap } from './style-map';
7
+ import supported from './supported';
8
+ import { upsertImportDeclaration } from './upsert-import-declaration';
9
+ const messageId = 'noRawSpacingValues';
10
+ export const StyleProperty = {
11
+ lint(node, {
12
+ context
13
+ }) {
14
+ // Check whether all criteria needed to make a transformation are met
15
+ const {
16
+ success,
17
+ ref
18
+ } = StyleProperty._check(node);
19
+ if (!success) {
20
+ return;
21
+ }
22
+ context.report({
23
+ node: ref.node.value,
24
+ messageId,
25
+ fix: ref.token ? StyleProperty._fix(ref, context) : undefined
26
+ });
27
+ },
28
+ _check(node) {
29
+ if (!isNodeOfType(node, 'Property')) {
30
+ return {
31
+ success: false,
32
+ ref: undefined
33
+ };
34
+ }
35
+
36
+ /**
37
+ * Currently, we support values like:
38
+ * ```
39
+ * {
40
+ * padding: '8px', // value.type is Literal
41
+ * margin: -8, // value.type is UnaryExpression
42
+ * }
43
+ * ```
44
+ */
45
+ if (!(isNodeOfType(node.value, 'Literal') || isNodeOfType(node.value, 'UnaryExpression'))) {
46
+ return {
47
+ success: false,
48
+ ref: undefined
49
+ };
50
+ }
51
+ const {
52
+ value: property
53
+ } = ast.ObjectEntry.getProperty(node);
54
+
55
+ // Bail if the property is not `padding`, `margin`, etc
56
+ if (!property || !styleMap[property]) {
57
+ return {
58
+ success: false,
59
+ ref: undefined
60
+ };
61
+ }
62
+ const value = ast.ObjectEntry.getValue(node);
63
+
64
+ // This is mainly useful as a type guard, so the checks after don't have to have duplicate checks for other types.
65
+ if (!isStringOrNumber(value)) {
66
+ return {
67
+ success: false,
68
+ ref: undefined
69
+ };
70
+ }
71
+
72
+ // ignore CSS vars. See: https://stash.atlassian.com/projects/ATLASSIAN/repos/atlassian-frontend-monorepo/pull-requests/74844/overview?commentId=6741571
73
+ if (value.toString().startsWith('var(')) {
74
+ return {
75
+ success: false,
76
+ ref: undefined
77
+ };
78
+ }
79
+
80
+ // There are valid values to ignore, such as `margin: auto`
81
+ if (supported.values.ignore.includes(value)) {
82
+ return {
83
+ success: false,
84
+ ref: undefined
85
+ };
86
+ }
87
+
88
+ // Don't report on stuff like `padding: '8px 16px'`.
89
+ // We may iterate to handle values like this in future.
90
+ if (value.toString().includes(' ')) {
91
+ return {
92
+ success: false,
93
+ ref: undefined
94
+ };
95
+ }
96
+ const ref = {
97
+ node,
98
+ token: styleMap[property][value],
99
+ fallback: value
100
+ };
101
+ return {
102
+ success: true,
103
+ ref
104
+ };
105
+ },
106
+ /**
107
+ * All required validation steps have been taken care of before this
108
+ * transformer is called, so it just goes ahead providing all necessary fixes
109
+ */
110
+ _fix(ref, context) {
111
+ return fixer => {
112
+ const importFix = upsertImportDeclaration({
113
+ module: '@atlaskit/tokens',
114
+ specifiers: ['token']
115
+ }, context, fixer);
116
+ const tokenCall = ref.fallback ? `token('${ref.token}', '${ref.fallback}')` : `token('${ref.token}')`;
117
+ const tokenFix = fixer.replaceText(ref.node.value, tokenCall);
118
+ return [importFix, tokenFix].filter(fix => Boolean(fix)); // Some of the transformers can return arrays with undefined, so filter them out
119
+ };
120
+ }
121
+ };