@atlaskit/eslint-plugin-design-system 8.27.0 → 8.29.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 (107) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +31 -29
  3. package/constellation/consistent-css-prop-usage/usage.mdx +193 -0
  4. package/constellation/ensure-design-token-usage/usage.mdx +72 -0
  5. package/constellation/ensure-design-token-usage-preview/usage.mdx +5 -0
  6. package/constellation/icon-label/usage.mdx +39 -0
  7. package/constellation/index/usage.mdx +31 -1508
  8. package/constellation/local-cx-xcss/usage.mdx +37 -0
  9. package/constellation/no-banned-imports/usage.mdx +17 -0
  10. package/constellation/no-css-tagged-template-expression/usage.mdx +66 -0
  11. package/constellation/no-deprecated-apis/usage.mdx +76 -0
  12. package/constellation/no-deprecated-design-token-usage/usage.mdx +27 -0
  13. package/constellation/no-deprecated-imports/usage.mdx +62 -0
  14. package/constellation/no-empty-styled-expression/usage.mdx +77 -0
  15. package/constellation/no-exported-css/usage.mdx +50 -0
  16. package/constellation/no-exported-keyframes/usage.mdx +50 -0
  17. package/constellation/no-invalid-css-map/usage.mdx +199 -0
  18. package/constellation/no-keyframes-tagged-template-expression/usage.mdx +76 -0
  19. package/constellation/no-margin/usage.mdx +20 -0
  20. package/constellation/no-nested-styles/usage.mdx +47 -0
  21. package/constellation/no-physical-properties/usage.mdx +53 -0
  22. package/constellation/no-styled-tagged-template-expression/usage.mdx +90 -0
  23. package/constellation/no-unsafe-design-token-usage/usage.mdx +49 -0
  24. package/constellation/no-unsafe-style-overrides/usage.mdx +49 -0
  25. package/constellation/no-unsupported-drag-and-drop-libraries/usage.mdx +17 -0
  26. package/constellation/prefer-primitives/usage.mdx +31 -0
  27. package/constellation/use-button-group-label/usage.mdx +58 -0
  28. package/constellation/use-drawer-label/usage.mdx +53 -0
  29. package/constellation/use-heading-level-in-spotlight-card/usage.mdx +20 -0
  30. package/constellation/use-href-in-link-item/usage.mdx +18 -0
  31. package/constellation/use-primitives/usage.mdx +77 -0
  32. package/constellation/use-visually-hidden/usage.mdx +34 -0
  33. package/dist/cjs/presets/all.codegen.js +3 -1
  34. package/dist/cjs/rules/index.codegen.js +5 -1
  35. package/dist/cjs/rules/no-css-tagged-template-expression/index.js +3 -2
  36. package/dist/cjs/rules/no-keyframes-tagged-template-expression/index.js +27 -0
  37. package/dist/cjs/rules/no-styled-tagged-template-expression/index.js +27 -0
  38. package/dist/cjs/rules/no-styled-tagged-template-expression/is-styled.js +53 -0
  39. package/dist/cjs/rules/use-primitives/transformers/css-to-xcss.js +17 -3
  40. package/dist/cjs/rules/use-primitives/utils/is-valid-css-properties-to-transform.js +7 -0
  41. package/dist/cjs/rules/{no-css-tagged-template-expression → utils}/create-no-tagged-template-expression-rule/index.js +26 -6
  42. package/dist/cjs/rules/{no-css-tagged-template-expression → utils}/create-no-tagged-template-expression-rule/to-arguments.js +28 -2
  43. package/dist/cjs/rules/utils/create-rule.js +7 -5
  44. package/dist/cjs/rules/utils/is-supported-import.js +7 -10
  45. package/dist/es2019/presets/all.codegen.js +3 -1
  46. package/dist/es2019/rules/index.codegen.js +5 -1
  47. package/dist/es2019/rules/no-css-tagged-template-expression/index.js +3 -2
  48. package/dist/es2019/rules/no-keyframes-tagged-template-expression/index.js +21 -0
  49. package/dist/es2019/rules/no-styled-tagged-template-expression/index.js +21 -0
  50. package/dist/es2019/rules/no-styled-tagged-template-expression/is-styled.js +45 -0
  51. package/dist/es2019/rules/use-primitives/transformers/css-to-xcss.js +13 -1
  52. package/dist/es2019/rules/use-primitives/utils/is-valid-css-properties-to-transform.js +6 -1
  53. package/dist/es2019/rules/utils/create-no-tagged-template-expression-rule/index.js +84 -0
  54. package/dist/es2019/rules/{no-css-tagged-template-expression → utils}/create-no-tagged-template-expression-rule/to-arguments.js +28 -2
  55. package/dist/es2019/rules/utils/create-rule.js +7 -5
  56. package/dist/es2019/rules/utils/is-supported-import.js +7 -8
  57. package/dist/esm/presets/all.codegen.js +3 -1
  58. package/dist/esm/rules/index.codegen.js +5 -1
  59. package/dist/esm/rules/no-css-tagged-template-expression/index.js +3 -2
  60. package/dist/esm/rules/no-keyframes-tagged-template-expression/index.js +21 -0
  61. package/dist/esm/rules/no-styled-tagged-template-expression/index.js +21 -0
  62. package/dist/esm/rules/no-styled-tagged-template-expression/is-styled.js +47 -0
  63. package/dist/esm/rules/use-primitives/transformers/css-to-xcss.js +16 -2
  64. package/dist/esm/rules/use-primitives/utils/is-valid-css-properties-to-transform.js +8 -1
  65. package/dist/esm/rules/{no-css-tagged-template-expression → utils}/create-no-tagged-template-expression-rule/index.js +25 -5
  66. package/dist/esm/rules/{no-css-tagged-template-expression → utils}/create-no-tagged-template-expression-rule/to-arguments.js +28 -2
  67. package/dist/esm/rules/utils/create-rule.js +7 -5
  68. package/dist/esm/rules/utils/is-supported-import.js +7 -9
  69. package/dist/types/index.codegen.d.ts +2 -0
  70. package/dist/types/presets/all.codegen.d.ts +3 -1
  71. package/dist/types/rules/index.codegen.d.ts +2 -0
  72. package/dist/types/rules/no-keyframes-tagged-template-expression/index.d.ts +2 -0
  73. package/dist/types/rules/no-styled-tagged-template-expression/index.d.ts +2 -0
  74. package/dist/types/rules/no-styled-tagged-template-expression/is-styled.d.ts +7 -0
  75. package/dist/types/rules/use-primitives/config/index.d.ts +1 -1
  76. package/dist/types/rules/use-primitives/transformers/css-to-xcss.d.ts +6 -0
  77. package/dist/types/rules/{no-css-tagged-template-expression → utils}/create-no-tagged-template-expression-rule/index.d.ts +3 -1
  78. package/dist/types/rules/{no-css-tagged-template-expression → utils}/create-no-tagged-template-expression-rule/types.d.ts +3 -0
  79. package/dist/types/rules/utils/is-supported-import.d.ts +5 -5
  80. package/dist/types-ts4.5/index.codegen.d.ts +2 -0
  81. package/dist/types-ts4.5/presets/all.codegen.d.ts +3 -1
  82. package/dist/types-ts4.5/rules/index.codegen.d.ts +2 -0
  83. package/dist/types-ts4.5/rules/no-keyframes-tagged-template-expression/index.d.ts +2 -0
  84. package/dist/types-ts4.5/rules/no-styled-tagged-template-expression/index.d.ts +2 -0
  85. package/dist/types-ts4.5/rules/no-styled-tagged-template-expression/is-styled.d.ts +7 -0
  86. package/dist/types-ts4.5/rules/use-primitives/config/index.d.ts +1 -1
  87. package/dist/types-ts4.5/rules/use-primitives/transformers/css-to-xcss.d.ts +6 -0
  88. package/dist/types-ts4.5/rules/{no-css-tagged-template-expression → utils}/create-no-tagged-template-expression-rule/index.d.ts +3 -1
  89. package/dist/types-ts4.5/rules/{no-css-tagged-template-expression → utils}/create-no-tagged-template-expression-rule/types.d.ts +3 -0
  90. package/dist/types-ts4.5/rules/utils/is-supported-import.d.ts +5 -5
  91. package/package.json +1 -1
  92. package/dist/es2019/rules/no-css-tagged-template-expression/create-no-tagged-template-expression-rule/index.js +0 -62
  93. /package/dist/cjs/rules/{no-css-tagged-template-expression → utils}/create-no-tagged-template-expression-rule/generate.js +0 -0
  94. /package/dist/cjs/rules/{no-css-tagged-template-expression → utils}/create-no-tagged-template-expression-rule/get-tagged-template-expression-offset.js +0 -0
  95. /package/dist/cjs/rules/{no-css-tagged-template-expression → utils}/create-no-tagged-template-expression-rule/types.js +0 -0
  96. /package/dist/es2019/rules/{no-css-tagged-template-expression → utils}/create-no-tagged-template-expression-rule/generate.js +0 -0
  97. /package/dist/es2019/rules/{no-css-tagged-template-expression → utils}/create-no-tagged-template-expression-rule/get-tagged-template-expression-offset.js +0 -0
  98. /package/dist/es2019/rules/{no-css-tagged-template-expression → utils}/create-no-tagged-template-expression-rule/types.js +0 -0
  99. /package/dist/esm/rules/{no-css-tagged-template-expression → utils}/create-no-tagged-template-expression-rule/generate.js +0 -0
  100. /package/dist/esm/rules/{no-css-tagged-template-expression → utils}/create-no-tagged-template-expression-rule/get-tagged-template-expression-offset.js +0 -0
  101. /package/dist/esm/rules/{no-css-tagged-template-expression → utils}/create-no-tagged-template-expression-rule/types.js +0 -0
  102. /package/dist/types/rules/{no-css-tagged-template-expression → utils}/create-no-tagged-template-expression-rule/generate.d.ts +0 -0
  103. /package/dist/types/rules/{no-css-tagged-template-expression → utils}/create-no-tagged-template-expression-rule/get-tagged-template-expression-offset.d.ts +0 -0
  104. /package/dist/types/rules/{no-css-tagged-template-expression → utils}/create-no-tagged-template-expression-rule/to-arguments.d.ts +0 -0
  105. /package/dist/types-ts4.5/rules/{no-css-tagged-template-expression → utils}/create-no-tagged-template-expression-rule/generate.d.ts +0 -0
  106. /package/dist/types-ts4.5/rules/{no-css-tagged-template-expression → utils}/create-no-tagged-template-expression-rule/get-tagged-template-expression-offset.d.ts +0 -0
  107. /package/dist/types-ts4.5/rules/{no-css-tagged-template-expression → utils}/create-no-tagged-template-expression-rule/to-arguments.d.ts +0 -0
@@ -0,0 +1,84 @@
1
+ // Original source from Compiled https://github.com/atlassian-labs/compiled/blob/master/packages/eslint-plugin/src/utils/create-no-tagged-template-expression-rule/index.ts
2
+ // eslint-disable-next-line import/no-extraneous-dependencies
3
+
4
+ import { getImportSources } from '../is-supported-import';
5
+ import { generate } from './generate';
6
+ import { getTaggedTemplateExpressionOffset } from './get-tagged-template-expression-offset';
7
+ import { toArguments } from './to-arguments';
8
+ export const noTaggedTemplateExpressionRuleSchema = [{
9
+ type: 'object',
10
+ properties: {
11
+ importSources: {
12
+ type: 'array',
13
+ items: {
14
+ type: 'string'
15
+ },
16
+ uniqueItems: true
17
+ }
18
+ }
19
+ }];
20
+
21
+ /**
22
+ * When true, template strings containing multiline comments are completely skipped over.
23
+ *
24
+ * When false, multiline comments are stripped out. Ideally we would preserve them,
25
+ * but it would add a lot of complexity.
26
+ */
27
+ const shouldSkipMultilineComments = false;
28
+ export const createNoTaggedTemplateExpressionRule = (isUsage, messageId) => context => {
29
+ const importSources = getImportSources(context);
30
+ return {
31
+ TaggedTemplateExpression(node) {
32
+ const {
33
+ references
34
+ } = context.getScope();
35
+ if (!isUsage(node.tag, references, importSources)) {
36
+ return;
37
+ }
38
+ context.report({
39
+ messageId,
40
+ node,
41
+ *fix(fixer) {
42
+ const {
43
+ quasi
44
+ } = node;
45
+ const source = context.getSourceCode();
46
+
47
+ // TODO Eventually handle comments instead of skipping them
48
+ // Skip auto-fixing comments
49
+ if (shouldSkipMultilineComments && quasi.quasis.map(q => q.value.raw).join('').match(/\/\*[\s\S]*\*\//g)) {
50
+ return;
51
+ }
52
+
53
+ // Replace empty tagged template expression with the equivalent object call expression
54
+ if (!quasi.expressions.length && quasi.quasis.length === 1 && !quasi.quasis[0].value.raw.trim()) {
55
+ yield fixer.replaceText(quasi, '({})');
56
+ return;
57
+ }
58
+ const args = toArguments(source, quasi);
59
+
60
+ // Skip invalid CSS
61
+ if (args.length < 1) {
62
+ return;
63
+ }
64
+ const oldCode = source.getText(node);
65
+ // Remove quasi:
66
+ // styled.div<Props>`
67
+ // color: red;
68
+ // `
69
+ // becomes
70
+ // styled.div<Props>
71
+ const withoutQuasi = oldCode.replace(source.getText(quasi), '');
72
+ const newCode = withoutQuasi +
73
+ // Indent the arguments after the tagged template expression range
74
+ generate(args, getTaggedTemplateExpressionOffset(node));
75
+ if (oldCode === newCode) {
76
+ return;
77
+ }
78
+ yield fixer.insertTextBefore(node, newCode);
79
+ yield fixer.remove(node);
80
+ }
81
+ });
82
+ }
83
+ };
84
+ };
@@ -39,7 +39,30 @@ const getArguments = (chars, expressions = []) => {
39
39
  }
40
40
  }
41
41
  const getValue = () => {
42
- if (!value.trim().length && expressions.length) {
42
+ /**
43
+ * This branch is required for handling interpolated functions:
44
+ *
45
+ * css`
46
+ * color: ${(props) => props.textColor}
47
+ * `
48
+ *
49
+ * But it also breaks interpolations of multiple tokens:
50
+ *
51
+ * css`
52
+ * padding: ${token('space.100')} ${token('space.200')}
53
+ * `
54
+ *
55
+ * which becomes invalid syntax:
56
+ *
57
+ * css({
58
+ * padding: token('space.100')token('space.200')
59
+ * })
60
+ *
61
+ * Limiting this branch to when `expressions.length === 1` seems
62
+ * to allow both cases to work. There may be other edge cases,
63
+ * but none were caught by the existing test suite.
64
+ */
65
+ if (!value.trim().length && expressions.length === 1) {
43
66
  return {
44
67
  type: 'expression',
45
68
  expression: expressions.map(e => e.expression).join('')
@@ -134,7 +157,10 @@ export const toArguments = (source, template) => {
134
157
  };
135
158
  for (const [i, quasi] of template.quasis.entries()) {
136
159
  // Deal with selectors across multiple lines
137
- const styleTemplateElement = quasi.value.raw.replace(/(\r\n|\n|\r)/gm, ' ').replace(/\s+/g, ' ');
160
+ const styleTemplateElement = quasi.value.raw.replace(/\/\*(.|\n|\r)*?\*\//g, '') // Removes multi-line comments
161
+ // Remove single line comments
162
+ // Negative lookbehind to handle URL-like double slashes
163
+ .replace(/(?<!https?:)\/\/.*$/gm, '').replace(/(\r\n|\n|\r)/gm, ' ').replace(/\s+/g, ' ');
138
164
  for (const char of styleTemplateElement) {
139
165
  switch (char) {
140
166
  case '{':
@@ -10,15 +10,17 @@ import { ESLintUtils } from '@typescript-eslint/utils';
10
10
  * @private
11
11
  * @deprecated
12
12
  */
13
- export const createRule = ESLintUtils.RuleCreator(name => `https://atlassian.design/components/eslint-plugin-design-system/usage#${name}`);
13
+ export const createRule = ESLintUtils.RuleCreator(name => getRuleUrl(name));
14
14
  /**
15
15
  * Tiny wrapped over the ESLint rule module type that ensures
16
16
  * there is a docs link to our ESLint plugin documentation page,
17
17
  * as well as improving type support.
18
18
  */
19
19
  export const createLintRule = rule => {
20
- const ruleName = rule.meta.name.replace('/', ''); // If it's a nested rule, ensure the url is clean
21
- const url = `https://atlassian.design/components/eslint-plugin-design-system/usage#${ruleName}`;
22
- rule.meta.docs.url = url;
20
+ rule.meta.docs.url = getRuleUrl(rule.meta.name);
23
21
  return rule;
24
- };
22
+ };
23
+ function getRuleUrl(ruleName) {
24
+ const name = ruleName.replace('/', '-'); // If it's a nested rule, ensure the url is clean and matches codegen/gatsby
25
+ return `https://atlassian.design/components/eslint-plugin-design-system/${name}/usage`;
26
+ }
@@ -4,6 +4,7 @@ export const CSS_IN_JS_IMPORTS = {
4
4
  compiled: '@compiled/react',
5
5
  emotionReact: '@emotion/react',
6
6
  emotionCore: '@emotion/core',
7
+ emotionStyled: '@emotion/styled',
7
8
  styledComponents: 'styled-components',
8
9
  atlaskitCss: '@atlaskit/css',
9
10
  atlaskitPrimitives: '@atlaskit/primitives'
@@ -11,16 +12,14 @@ export const CSS_IN_JS_IMPORTS = {
11
12
 
12
13
  // A CSS-in-JS library an import of a valid css, cx, cssMap, etc.
13
14
  // function might originate from, e.g. @compiled/react, @emotion/core.
14
- // All ESLint rules originating from `@compiled/eslint-plugin` should apply to these libraries.
15
- export const DEFAULT_IMPORT_SOURCES = [CSS_IN_JS_IMPORTS.compiled, CSS_IN_JS_IMPORTS.atlaskitCss];
15
+ /**
16
+ * By default all known import sources are checked against.
17
+ */
18
+ export const DEFAULT_IMPORT_SOURCES = Object.values(CSS_IN_JS_IMPORTS);
16
19
 
17
20
  /**
18
21
  * Given the ESLint rule context, extract and parse the value of the importSources rule option.
19
- * The importSources option is used to define additional libraries for which an ESLint rule
20
- * should apply to.
21
- *
22
- * Note that `@compiled/react` and `@atlaskit/css` are always included in importSources, regardless
23
- * of what importSources is configured to by the user.
22
+ * The importSources option is used to override which libraries an ESLint rule applies to.
24
23
  *
25
24
  * @param context The rule context.
26
25
  * @returns An array of strings representing what CSS-in-JS packages that should be checked, based
@@ -32,7 +31,7 @@ export const getImportSources = context => {
32
31
  return DEFAULT_IMPORT_SOURCES;
33
32
  }
34
33
  if (options[0].importSources && Array.isArray(options[0].importSources)) {
35
- return [...DEFAULT_IMPORT_SOURCES, ...options[0].importSources];
34
+ return options[0].importSources;
36
35
  }
37
36
  return DEFAULT_IMPORT_SOURCES;
38
37
  };
@@ -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::914085544778f4543f43e3e30d0982e0>>
3
+ * @codegen <<SignedSource::5647ce9c10ba880cffece66b5924fd6e>>
4
4
  * @codegenCommand yarn workspace @atlaskit/eslint-plugin-design-system codegen
5
5
  */
6
6
  export default {
@@ -20,9 +20,11 @@ export default {
20
20
  '@atlaskit/design-system/no-exported-css': 'warn',
21
21
  '@atlaskit/design-system/no-exported-keyframes': 'warn',
22
22
  '@atlaskit/design-system/no-invalid-css-map': 'error',
23
+ '@atlaskit/design-system/no-keyframes-tagged-template-expression': 'error',
23
24
  '@atlaskit/design-system/no-margin': 'warn',
24
25
  '@atlaskit/design-system/no-nested-styles': 'error',
25
26
  '@atlaskit/design-system/no-physical-properties': 'error',
27
+ '@atlaskit/design-system/no-styled-tagged-template-expression': 'error',
26
28
  '@atlaskit/design-system/no-unsafe-design-token-usage': 'error',
27
29
  '@atlaskit/design-system/no-unsafe-style-overrides': 'warn',
28
30
  '@atlaskit/design-system/no-unsupported-drag-and-drop-libraries': 'error',
@@ -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::0a2d88c9772eb438048415f13550f592>>
3
+ * @codegen <<SignedSource::0a2813f0b87e94d23e1f6fc388539c70>>
4
4
  * @codegenCommand yarn workspace @atlaskit/eslint-plugin-design-system codegen
5
5
  */
6
6
  import consistentCssPropUsage from './consistent-css-prop-usage';
@@ -17,9 +17,11 @@ import noEmptyStyledExpression from './no-empty-styled-expression';
17
17
  import noExportedCss from './no-exported-css';
18
18
  import noExportedKeyframes from './no-exported-keyframes';
19
19
  import noInvalidCssMap from './no-invalid-css-map';
20
+ import noKeyframesTaggedTemplateExpression from './no-keyframes-tagged-template-expression';
20
21
  import noMargin from './no-margin';
21
22
  import noNestedStyles from './no-nested-styles';
22
23
  import noPhysicalProperties from './no-physical-properties';
24
+ import noStyledTaggedTemplateExpression from './no-styled-tagged-template-expression';
23
25
  import noUnsafeDesignTokenUsage from './no-unsafe-design-token-usage';
24
26
  import noUnsafeStyleOverrides from './no-unsafe-style-overrides';
25
27
  import noUnsupportedDragAndDropLibraries from './no-unsupported-drag-and-drop-libraries';
@@ -45,9 +47,11 @@ export default {
45
47
  'no-exported-css': noExportedCss,
46
48
  'no-exported-keyframes': noExportedKeyframes,
47
49
  'no-invalid-css-map': noInvalidCssMap,
50
+ 'no-keyframes-tagged-template-expression': noKeyframesTaggedTemplateExpression,
48
51
  'no-margin': noMargin,
49
52
  'no-nested-styles': noNestedStyles,
50
53
  'no-physical-properties': noPhysicalProperties,
54
+ 'no-styled-tagged-template-expression': noStyledTaggedTemplateExpression,
51
55
  'no-unsafe-design-token-usage': noUnsafeDesignTokenUsage,
52
56
  'no-unsafe-style-overrides': noUnsafeStyleOverrides,
53
57
  'no-unsupported-drag-and-drop-libraries': noUnsupportedDragAndDropLibraries,
@@ -1,6 +1,6 @@
1
+ import { createNoTaggedTemplateExpressionRule, noTaggedTemplateExpressionRuleSchema } from '../utils/create-no-tagged-template-expression-rule';
1
2
  import { createLintRule } from '../utils/create-rule';
2
3
  import { isCss } from '../utils/is-supported-import';
3
- import { createNoTaggedTemplateExpressionRule } from './create-no-tagged-template-expression-rule';
4
4
  var rule = createLintRule({
5
5
  meta: {
6
6
  name: 'no-css-tagged-template-expression',
@@ -13,7 +13,8 @@ var rule = createLintRule({
13
13
  },
14
14
  messages: {
15
15
  unexpectedTaggedTemplate: 'Unexpected `css` tagged template expression'
16
- }
16
+ },
17
+ schema: noTaggedTemplateExpressionRuleSchema
17
18
  },
18
19
  create: createNoTaggedTemplateExpressionRule(isCss, 'unexpectedTaggedTemplate')
19
20
  });
@@ -0,0 +1,21 @@
1
+ import { createNoTaggedTemplateExpressionRule, noTaggedTemplateExpressionRuleSchema } from '../utils/create-no-tagged-template-expression-rule';
2
+ import { createLintRule } from '../utils/create-rule';
3
+ import { isKeyframes } from '../utils/is-supported-import';
4
+ var rule = createLintRule({
5
+ meta: {
6
+ name: 'no-keyframes-tagged-template-expression',
7
+ fixable: 'code',
8
+ type: 'problem',
9
+ docs: {
10
+ description: 'Disallows any `keyframe` tagged template expressions that originate from Emotion, Styled Components or Compiled',
11
+ recommended: false,
12
+ severity: 'error'
13
+ },
14
+ messages: {
15
+ unexpectedTaggedTemplate: 'Unexpected `keyframes` tagged template expression'
16
+ },
17
+ schema: noTaggedTemplateExpressionRuleSchema
18
+ },
19
+ create: createNoTaggedTemplateExpressionRule(isKeyframes, 'unexpectedTaggedTemplate')
20
+ });
21
+ export default rule;
@@ -0,0 +1,21 @@
1
+ import { createNoTaggedTemplateExpressionRule, noTaggedTemplateExpressionRuleSchema } from '../utils/create-no-tagged-template-expression-rule';
2
+ import { createLintRule } from '../utils/create-rule';
3
+ import { isStyled } from './is-styled';
4
+ var rule = createLintRule({
5
+ meta: {
6
+ name: 'no-styled-tagged-template-expression',
7
+ fixable: 'code',
8
+ type: 'problem',
9
+ docs: {
10
+ description: 'Disallows any `styled` tagged template expressions that originate from Emotion, Styled Components or Compiled',
11
+ recommended: false,
12
+ severity: 'error'
13
+ },
14
+ messages: {
15
+ unexpectedTaggedTemplate: 'Unexpected `styled` tagged template expression'
16
+ },
17
+ schema: noTaggedTemplateExpressionRuleSchema
18
+ },
19
+ create: createNoTaggedTemplateExpressionRule(isStyled, 'unexpectedTaggedTemplate')
20
+ });
21
+ export default rule;
@@ -0,0 +1,47 @@
1
+ // eslint-disable-next-line import/no-extraneous-dependencies
2
+
3
+ import { CSS_IN_JS_IMPORTS } from '../utils/is-supported-import';
4
+ var functionName = 'styled';
5
+ var checkDefinitionHasImport = function checkDefinitionHasImport(def, importSources) {
6
+ if (def.type !== 'ImportBinding') {
7
+ return false;
8
+ }
9
+ if (!def.parent || !importSources.includes(def.parent.source.value)) {
10
+ return false;
11
+ }
12
+
13
+ // `@compiled/react` only exposes styled as a named export
14
+ if (importSources.includes(CSS_IN_JS_IMPORTS.compiled) && def.parent.source.value === CSS_IN_JS_IMPORTS.compiled) {
15
+ return def.node.type === 'ImportSpecifier' && def.node.imported.name === functionName;
16
+ }
17
+
18
+ // `@emotion/styled` only exposes styled as a default export
19
+ if (importSources.includes(CSS_IN_JS_IMPORTS.emotionStyled) && def.parent.source.value === CSS_IN_JS_IMPORTS.emotionStyled) {
20
+ return def.node.type === 'ImportDefaultSpecifier';
21
+ }
22
+
23
+ // `styled-components` only exposes styled as a default export
24
+ if (importSources.includes(CSS_IN_JS_IMPORTS.styledComponents) && def.parent.source.value === CSS_IN_JS_IMPORTS.styledComponents) {
25
+ return def.node.type === 'ImportDefaultSpecifier';
26
+ }
27
+ return false;
28
+ };
29
+ export var isStyled = function isStyled(nodeToCheck, referencesInScope, importSources) {
30
+ var nodeIdentifier = null;
31
+
32
+ // Handles styled.div`` case
33
+ if (nodeToCheck.type === 'MemberExpression' && nodeToCheck.object.type === 'Identifier') {
34
+ nodeIdentifier = nodeToCheck.object;
35
+ }
36
+
37
+ // Handles styled(Base)`` case
38
+ if (nodeToCheck.type === 'CallExpression' && nodeToCheck.callee.type === 'Identifier') {
39
+ nodeIdentifier = nodeToCheck.callee;
40
+ }
41
+ return referencesInScope.some(function (reference) {
42
+ var _reference$resolved;
43
+ return reference.identifier === nodeIdentifier && ((_reference$resolved = reference.resolved) === null || _reference$resolved === void 0 ? void 0 : _reference$resolved.defs.some(function (def) {
44
+ return checkDefinitionHasImport(def, importSources);
45
+ }));
46
+ });
47
+ };
@@ -1,4 +1,7 @@
1
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
1
2
  import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
3
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
4
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
2
5
  import { getIdentifierInParentScope, identifier, isNodeOfType, literal } from 'eslint-codemod-utils';
3
6
  import { getAttributeValueIdentifier, getFunctionArgumentAtPos, getJSXAttributeByName, getVariableDefinitionValue } from '../utils';
4
7
  export var cssToXcssTransformer = function cssToXcssTransformer(node, context, fixer) {
@@ -83,7 +86,18 @@ export var spaceTokenMap = {
83
86
  '64px': 'space.800',
84
87
  '80px': 'space.1000'
85
88
  };
86
- export var supportedStylesMap = {
89
+ export var dimensionsMap = {
90
+ '100%': '100%'
91
+ };
92
+ export var supportedDimensionAttributesMap = {
93
+ width: dimensionsMap,
94
+ height: dimensionsMap,
95
+ minWidth: dimensionsMap,
96
+ minHeight: dimensionsMap,
97
+ maxWidth: dimensionsMap,
98
+ maxHeight: dimensionsMap
99
+ };
100
+ export var supportedStylesMap = _objectSpread({
87
101
  padding: spaceTokenMap,
88
102
  paddingBlock: spaceTokenMap,
89
103
  paddingBlockEnd: spaceTokenMap,
@@ -106,4 +120,4 @@ export var supportedStylesMap = {
106
120
  marginLeft: spaceTokenMap,
107
121
  marginRight: spaceTokenMap,
108
122
  marginTop: spaceTokenMap
109
- };
123
+ }, supportedDimensionAttributesMap);
@@ -3,7 +3,7 @@ import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProper
3
3
  var _excluded = ["unsupported"];
4
4
  import { isNodeOfType } from 'eslint-codemod-utils';
5
5
  import * as ast from '../../../ast-nodes';
6
- import { supportedStylesMap } from '../transformers/css-to-xcss';
6
+ import { supportedDimensionAttributesMap, supportedStylesMap } from '../transformers/css-to-xcss';
7
7
  import { convertASTObjectExpressionToJSObject } from './convert-ast-object-expression-to-js-object';
8
8
  export var isValidCssPropertiesToTransform = function isValidCssPropertiesToTransform(node, config) {
9
9
  if (!node) {
@@ -40,6 +40,13 @@ export var isValidCssPropertiesToTransform = function isValidCssPropertiesToTran
40
40
  return false;
41
41
  }
42
42
 
43
+ // Short-circuit when dimension properties found but pattern is not enabled in config
44
+ if (!config.patterns.includes('dimension-properties') && Object.keys(cssObject).some(function (attribute) {
45
+ return supportedDimensionAttributesMap[attribute];
46
+ })) {
47
+ return false;
48
+ }
49
+
43
50
  // NOTE: Our approach with this lint rule is to strictly whitelist css properties we can map.
44
51
  // It means we have to provide mappings for everything (e.g. `display: block`).
45
52
  // However, from a maker's experience, it's much better that the rule doesn't report (if we miss a mapping)
@@ -2,18 +2,38 @@ import _regeneratorRuntime from "@babel/runtime/regenerator";
2
2
  // Original source from Compiled https://github.com/atlassian-labs/compiled/blob/master/packages/eslint-plugin/src/utils/create-no-tagged-template-expression-rule/index.ts
3
3
  // eslint-disable-next-line import/no-extraneous-dependencies
4
4
 
5
- import { CSS_IN_JS_IMPORTS } from '../../utils/is-supported-import';
5
+ import { getImportSources } from '../is-supported-import';
6
6
  import { generate } from './generate';
7
7
  import { getTaggedTemplateExpressionOffset } from './get-tagged-template-expression-offset';
8
8
  import { toArguments } from './to-arguments';
9
- var IMPORT_SOURCES = [CSS_IN_JS_IMPORTS.compiled, CSS_IN_JS_IMPORTS.emotionReact, CSS_IN_JS_IMPORTS.emotionCore, CSS_IN_JS_IMPORTS.styledComponents];
9
+ export var noTaggedTemplateExpressionRuleSchema = [{
10
+ type: 'object',
11
+ properties: {
12
+ importSources: {
13
+ type: 'array',
14
+ items: {
15
+ type: 'string'
16
+ },
17
+ uniqueItems: true
18
+ }
19
+ }
20
+ }];
21
+
22
+ /**
23
+ * When true, template strings containing multiline comments are completely skipped over.
24
+ *
25
+ * When false, multiline comments are stripped out. Ideally we would preserve them,
26
+ * but it would add a lot of complexity.
27
+ */
28
+ var shouldSkipMultilineComments = false;
10
29
  export var createNoTaggedTemplateExpressionRule = function createNoTaggedTemplateExpressionRule(isUsage, messageId) {
11
30
  return function (context) {
31
+ var importSources = getImportSources(context);
12
32
  return {
13
33
  TaggedTemplateExpression: function TaggedTemplateExpression(node) {
14
34
  var _context$getScope = context.getScope(),
15
35
  references = _context$getScope.references;
16
- if (!isUsage(node.tag, references, IMPORT_SOURCES)) {
36
+ if (!isUsage(node.tag, references, importSources)) {
17
37
  return;
18
38
  }
19
39
  context.report({
@@ -27,9 +47,9 @@ export var createNoTaggedTemplateExpressionRule = function createNoTaggedTemplat
27
47
  quasi = node.quasi;
28
48
  source = context.getSourceCode(); // TODO Eventually handle comments instead of skipping them
29
49
  // Skip auto-fixing comments
30
- if (!quasi.quasis.map(function (q) {
50
+ if (!(shouldSkipMultilineComments && quasi.quasis.map(function (q) {
31
51
  return q.value.raw;
32
- }).join('').match(/\/\*[\s\S]*\*\//g)) {
52
+ }).join('').match(/\/\*[\s\S]*\*\//g))) {
33
53
  _context.next = 4;
34
54
  break;
35
55
  }
@@ -49,7 +49,30 @@ var getArguments = function getArguments(chars) {
49
49
  }
50
50
  }
51
51
  var getValue = function getValue() {
52
- if (!value.trim().length && expressions.length) {
52
+ /**
53
+ * This branch is required for handling interpolated functions:
54
+ *
55
+ * css`
56
+ * color: ${(props) => props.textColor}
57
+ * `
58
+ *
59
+ * But it also breaks interpolations of multiple tokens:
60
+ *
61
+ * css`
62
+ * padding: ${token('space.100')} ${token('space.200')}
63
+ * `
64
+ *
65
+ * which becomes invalid syntax:
66
+ *
67
+ * css({
68
+ * padding: token('space.100')token('space.200')
69
+ * })
70
+ *
71
+ * Limiting this branch to when `expressions.length === 1` seems
72
+ * to allow both cases to work. There may be other edge cases,
73
+ * but none were caught by the existing test suite.
74
+ */
75
+ if (!value.trim().length && expressions.length === 1) {
53
76
  return {
54
77
  type: 'expression',
55
78
  expression: expressions.map(function (e) {
@@ -177,7 +200,10 @@ export var toArguments = function toArguments(source, template) {
177
200
  i = _step4$value[0],
178
201
  quasi = _step4$value[1];
179
202
  // Deal with selectors across multiple lines
180
- var styleTemplateElement = quasi.value.raw.replace(/(\r\n|\n|\r)/gm, ' ').replace(/\s+/g, ' ');
203
+ var styleTemplateElement = quasi.value.raw.replace(/\/\*(.|\n|\r)*?\*\//g, '') // Removes multi-line comments
204
+ // Remove single line comments
205
+ // Negative lookbehind to handle URL-like double slashes
206
+ .replace(/(?<!https?:)\/\/.*$/gm, '').replace(/(\r\n|\n|\r)/gm, ' ').replace(/\s+/g, ' ');
181
207
  var _iterator5 = _createForOfIteratorHelper(styleTemplateElement),
182
208
  _step5;
183
209
  try {
@@ -11,7 +11,7 @@ import { ESLintUtils } from '@typescript-eslint/utils';
11
11
  * @deprecated
12
12
  */
13
13
  export var createRule = ESLintUtils.RuleCreator(function (name) {
14
- return "https://atlassian.design/components/eslint-plugin-design-system/usage#".concat(name);
14
+ return getRuleUrl(name);
15
15
  });
16
16
  /**
17
17
  * Tiny wrapped over the ESLint rule module type that ensures
@@ -19,8 +19,10 @@ export var createRule = ESLintUtils.RuleCreator(function (name) {
19
19
  * as well as improving type support.
20
20
  */
21
21
  export var createLintRule = function createLintRule(rule) {
22
- var ruleName = rule.meta.name.replace('/', ''); // If it's a nested rule, ensure the url is clean
23
- var url = "https://atlassian.design/components/eslint-plugin-design-system/usage#".concat(ruleName);
24
- rule.meta.docs.url = url;
22
+ rule.meta.docs.url = getRuleUrl(rule.meta.name);
25
23
  return rule;
26
- };
24
+ };
25
+ function getRuleUrl(ruleName) {
26
+ var name = ruleName.replace('/', '-'); // If it's a nested rule, ensure the url is clean and matches codegen/gatsby
27
+ return "https://atlassian.design/components/eslint-plugin-design-system/".concat(name, "/usage");
28
+ }
@@ -1,10 +1,10 @@
1
- import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
2
1
  // eslint-disable-next-line import/no-extraneous-dependencies
3
2
 
4
3
  export var CSS_IN_JS_IMPORTS = {
5
4
  compiled: '@compiled/react',
6
5
  emotionReact: '@emotion/react',
7
6
  emotionCore: '@emotion/core',
7
+ emotionStyled: '@emotion/styled',
8
8
  styledComponents: 'styled-components',
9
9
  atlaskitCss: '@atlaskit/css',
10
10
  atlaskitPrimitives: '@atlaskit/primitives'
@@ -12,16 +12,14 @@ export var CSS_IN_JS_IMPORTS = {
12
12
 
13
13
  // A CSS-in-JS library an import of a valid css, cx, cssMap, etc.
14
14
  // function might originate from, e.g. @compiled/react, @emotion/core.
15
- // All ESLint rules originating from `@compiled/eslint-plugin` should apply to these libraries.
16
- export var DEFAULT_IMPORT_SOURCES = [CSS_IN_JS_IMPORTS.compiled, CSS_IN_JS_IMPORTS.atlaskitCss];
15
+ /**
16
+ * By default all known import sources are checked against.
17
+ */
18
+ export var DEFAULT_IMPORT_SOURCES = Object.values(CSS_IN_JS_IMPORTS);
17
19
 
18
20
  /**
19
21
  * Given the ESLint rule context, extract and parse the value of the importSources rule option.
20
- * The importSources option is used to define additional libraries for which an ESLint rule
21
- * should apply to.
22
- *
23
- * Note that `@compiled/react` and `@atlaskit/css` are always included in importSources, regardless
24
- * of what importSources is configured to by the user.
22
+ * The importSources option is used to override which libraries an ESLint rule applies to.
25
23
  *
26
24
  * @param context The rule context.
27
25
  * @returns An array of strings representing what CSS-in-JS packages that should be checked, based
@@ -33,7 +31,7 @@ export var getImportSources = function getImportSources(context) {
33
31
  return DEFAULT_IMPORT_SOURCES;
34
32
  }
35
33
  if (options[0].importSources && Array.isArray(options[0].importSources)) {
36
- return [].concat(DEFAULT_IMPORT_SOURCES, _toConsumableArray(options[0].importSources));
34
+ return options[0].importSources;
37
35
  }
38
36
  return DEFAULT_IMPORT_SOURCES;
39
37
  };
@@ -17,9 +17,11 @@ export declare const configs: {
17
17
  '@atlaskit/design-system/no-exported-css': string;
18
18
  '@atlaskit/design-system/no-exported-keyframes': string;
19
19
  '@atlaskit/design-system/no-invalid-css-map': string;
20
+ '@atlaskit/design-system/no-keyframes-tagged-template-expression': string;
20
21
  '@atlaskit/design-system/no-margin': string;
21
22
  '@atlaskit/design-system/no-nested-styles': string;
22
23
  '@atlaskit/design-system/no-physical-properties': string;
24
+ '@atlaskit/design-system/no-styled-tagged-template-expression': string;
23
25
  '@atlaskit/design-system/no-unsafe-design-token-usage': string;
24
26
  '@atlaskit/design-system/no-unsafe-style-overrides': string;
25
27
  '@atlaskit/design-system/no-unsupported-drag-and-drop-libraries': string;
@@ -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::914085544778f4543f43e3e30d0982e0>>
3
+ * @codegen <<SignedSource::5647ce9c10ba880cffece66b5924fd6e>>
4
4
  * @codegenCommand yarn workspace @atlaskit/eslint-plugin-design-system codegen
5
5
  */
6
6
  declare const _default: {
@@ -20,9 +20,11 @@ declare const _default: {
20
20
  '@atlaskit/design-system/no-exported-css': string;
21
21
  '@atlaskit/design-system/no-exported-keyframes': string;
22
22
  '@atlaskit/design-system/no-invalid-css-map': string;
23
+ '@atlaskit/design-system/no-keyframes-tagged-template-expression': string;
23
24
  '@atlaskit/design-system/no-margin': string;
24
25
  '@atlaskit/design-system/no-nested-styles': string;
25
26
  '@atlaskit/design-system/no-physical-properties': string;
27
+ '@atlaskit/design-system/no-styled-tagged-template-expression': string;
26
28
  '@atlaskit/design-system/no-unsafe-design-token-usage': string;
27
29
  '@atlaskit/design-system/no-unsafe-style-overrides': string;
28
30
  '@atlaskit/design-system/no-unsupported-drag-and-drop-libraries': string;
@@ -17,9 +17,11 @@ declare const _default: {
17
17
  'no-exported-css': import("eslint").Rule.RuleModule;
18
18
  'no-exported-keyframes': import("eslint").Rule.RuleModule;
19
19
  'no-invalid-css-map': import("eslint").Rule.RuleModule;
20
+ 'no-keyframes-tagged-template-expression': import("eslint").Rule.RuleModule;
20
21
  'no-margin': import("eslint").Rule.RuleModule;
21
22
  'no-nested-styles': import("eslint").Rule.RuleModule;
22
23
  'no-physical-properties': import("eslint").Rule.RuleModule;
24
+ 'no-styled-tagged-template-expression': import("eslint").Rule.RuleModule;
23
25
  'no-unsafe-design-token-usage': import("eslint").Rule.RuleModule;
24
26
  'no-unsafe-style-overrides': import("eslint").Rule.RuleModule;
25
27
  'no-unsupported-drag-and-drop-libraries': import("eslint").Rule.RuleModule;
@@ -0,0 +1,2 @@
1
+ declare const rule: import("eslint").Rule.RuleModule;
2
+ export default rule;
@@ -0,0 +1,2 @@
1
+ declare const rule: import("eslint").Rule.RuleModule;
2
+ export default rule;
@@ -0,0 +1,7 @@
1
+ import type { Scope } from 'eslint';
2
+ import type { CallExpression } from 'estree';
3
+ import { ImportSource } from '../utils/is-supported-import';
4
+ type Callee = CallExpression['callee'];
5
+ type Reference = Scope.Reference;
6
+ export declare const isStyled: (nodeToCheck: Callee, referencesInScope: Reference[], importSources: ImportSource[]) => boolean;
7
+ export {};