@atlaskit/eslint-plugin-design-system 8.32.0 → 8.32.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,7 @@
1
1
  import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
2
  import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
3
+ import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
4
+ import _createClass from "@babel/runtime/helpers/createClass";
3
5
  import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
4
6
  // eslint-disable-next-line import/no-extraneous-dependencies
5
7
 
@@ -11,8 +13,6 @@ import { createLintRule } from '../utils/create-rule';
11
13
  import { getFirstSupportedImport } from '../utils/get-first-supported-import';
12
14
  import { getModuleOfIdentifier } from '../utils/get-import-node-by-source';
13
15
  import { CSS_IN_JS_IMPORTS } from '../utils/is-supported-import';
14
- // File-level tracking of styles hoisted from the cssAtTopOfModule/cssAtBottomOfModule fixers
15
- var hoistedCss = [];
16
16
  var isDOMElementName = function isDOMElementName(elementName) {
17
17
  return elementName.charAt(0) !== elementName.charAt(0).toUpperCase() && elementName.charAt(0) === elementName.charAt(0).toLowerCase();
18
18
  };
@@ -33,365 +33,408 @@ var getProgramNode = function getProgramNode(expression) {
33
33
  }
34
34
  return expression.parent;
35
35
  };
36
+ var JSXExpressionLinter = /*#__PURE__*/function () {
37
+ // File-level tracking of styles hoisted from the cssAtTopOfModule/cssAtBottomOfModule fixers.
36
38
 
37
- /**
38
- * Generates the declarator string when fixing the cssAtTopOfModule/cssAtBottomOfModule cases.
39
- * When `styles` already exists, `styles_1, styles_2, ..., styles_X` are incrementally created for each unhoisted style.
40
- * The generated `styles` varibale declaration names must be manually modified to be more informative at the discretion of owning teams.
41
- */
42
- var getDeclaratorString = function getDeclaratorString(context) {
43
- var scope = context.getScope();
44
-
45
- // Get to ModuleScope
46
- while (scope && scope.upper && scope.upper.type !== 'global') {
47
- var _scope;
48
- scope = (_scope = scope) === null || _scope === void 0 ? void 0 : _scope.upper;
39
+ /**
40
+ * Traverses and lints a expression found in a JSX css or xcss prop, e.g.
41
+ * <div css={expressionToLint} />
42
+ *
43
+ * @param context The context of the rule. Used to find the current scope and the source code of the file.
44
+ * @param cssAttributeName Used to encapsulate ObjectExpressions when cssAtTopOfModule/cssAtBottomOfModule violations are triggered.
45
+ * @param configuration What css-related functions to account for (eg. css, xcss, cssMap), and whether to detect bottom vs top expressions.
46
+ * @param expression The expression to traverse and lint.
47
+ */
48
+ function JSXExpressionLinter(context, cssAttributeName, configuration, expression) {
49
+ _classCallCheck(this, JSXExpressionLinter);
50
+ this.context = context;
51
+ this.cssAttributeName = cssAttributeName;
52
+ this.configuration = configuration;
53
+ this.expression = expression;
54
+ this.hoistedCss = [];
49
55
  }
50
- var variables = scope.variables.map(function (variable) {
51
- return variable.name;
52
- }).concat(hoistedCss);
53
- var count = 2;
54
- var declaratorName = 'styles';
55
56
 
56
- // Base case
57
- if (!variables.includes(declaratorName)) {
58
- return declaratorName;
59
- } else {
60
- // If styles already exists, increment the number
61
- while (variables.includes("".concat(declaratorName).concat(count))) {
62
- count++;
63
- }
64
- }
57
+ /**
58
+ * Generates the declarator string when fixing the cssAtTopOfModule/cssAtBottomOfModule cases.
59
+ * When `styles` already exists, `styles_1, styles_2, ..., styles_X` are incrementally created for each unhoisted style.
60
+ *
61
+ * The generated `styles` varibale declaration names must be manually modified to be more informative at the discretion of owning teams.
62
+ */
63
+ _createClass(JSXExpressionLinter, [{
64
+ key: "getDeclaratorString",
65
+ value: function getDeclaratorString() {
66
+ var scope = this.context.getScope();
65
67
 
66
- // Keep track of it by adding it to the hoistedCss global array
67
- hoistedCss = [].concat(_toConsumableArray(hoistedCss), ["".concat(declaratorName).concat(count)]);
68
- return "".concat(declaratorName).concat(count);
69
- };
70
- function analyzeIdentifier(context, sourceIdentifier, configuration, cssAttributeName) {
71
- var _getIdentifierInParen, _getIdentifierInParen2;
72
- var scope = context.getScope();
73
- var _ref = (_getIdentifierInParen = (_getIdentifierInParen2 = getIdentifierInParentScope(scope, sourceIdentifier.name)) === null || _getIdentifierInParen2 === void 0 ? void 0 : _getIdentifierInParen2.identifiers) !== null && _getIdentifierInParen !== void 0 ? _getIdentifierInParen : [],
74
- _ref2 = _slicedToArray(_ref, 1),
75
- identifier = _ref2[0];
76
- if (!identifier || !identifier.parent) {
77
- // Identifier isn't in the module, skip!
78
- return;
79
- }
80
- if (identifier.parent.type !== 'VariableDeclarator') {
81
- // When variable is not in the file or coming from import
82
- context.report({
83
- node: sourceIdentifier,
84
- messageId: 'cssInModule'
85
- });
86
- return;
87
- }
88
- if (identifier.parent.parent.parent.type !== 'Program') {
89
- // When variable is declared inside the component
90
- context.report({
91
- node: sourceIdentifier,
92
- messageId: configuration.stylesPlacement === 'bottom' ? 'cssAtBottomOfModule' : 'cssAtTopOfModule',
93
- fix: function fix(fixer) {
94
- if (configuration.fixNamesOnly) {
95
- return [];
68
+ // Get to ModuleScope
69
+ while (scope && scope.upper && scope.upper.type !== 'global') {
70
+ var _scope;
71
+ scope = (_scope = scope) === null || _scope === void 0 ? void 0 : _scope.upper;
72
+ }
73
+ var variables = scope.variables.map(function (variable) {
74
+ return variable.name;
75
+ }).concat(this.hoistedCss);
76
+ var count = 2;
77
+ var declaratorName = 'styles';
78
+
79
+ // Base case
80
+ if (!variables.includes(declaratorName)) {
81
+ return declaratorName;
82
+ } else {
83
+ // If styles already exists, increment the number
84
+ while (variables.includes("".concat(declaratorName).concat(count))) {
85
+ count++;
96
86
  }
97
- return fixCssNotInModuleScope(fixer, context, configuration, identifier);
98
87
  }
99
- });
100
- return;
101
- }
102
- if (identifier.parent && identifier.parent.init && !isCssCallExpression(identifier.parent.init, configuration.cssFunctions)) {
103
- // When variable value is not of type css({})
104
- var value = identifier.parent.init;
105
- if (!value) {
106
- return;
88
+
89
+ // Keep track of it by adding it to the hoistedCss global array
90
+ this.hoistedCss = [].concat(_toConsumableArray(this.hoistedCss), ["".concat(declaratorName).concat(count)]);
91
+ return "".concat(declaratorName).concat(count);
107
92
  }
108
- var valueExpression =
109
- // @ts-expect-error remove once eslint types are switched to @typescript-eslint
110
- value.type === 'TSAsExpression' ? value.expression : value;
111
- if (['ObjectExpression', 'TemplateLiteral'].includes(valueExpression.type)) {
112
- context.report({
113
- node: identifier,
114
- messageId: 'cssObjectTypeOnly',
115
- fix: function fix(fixer) {
116
- if (configuration.fixNamesOnly) {
117
- return [];
93
+ }, {
94
+ key: "analyzeIdentifier",
95
+ value: function analyzeIdentifier(sourceIdentifier) {
96
+ var _getIdentifierInParen,
97
+ _getIdentifierInParen2,
98
+ _this = this;
99
+ var scope = this.context.getScope();
100
+ var _ref = (_getIdentifierInParen = (_getIdentifierInParen2 = getIdentifierInParentScope(scope, sourceIdentifier.name)) === null || _getIdentifierInParen2 === void 0 ? void 0 : _getIdentifierInParen2.identifiers) !== null && _getIdentifierInParen !== void 0 ? _getIdentifierInParen : [],
101
+ _ref2 = _slicedToArray(_ref, 1),
102
+ identifier = _ref2[0];
103
+ if (!identifier || !identifier.parent) {
104
+ // Identifier isn't in the module, skip!
105
+ return;
106
+ }
107
+ if (identifier.parent.type !== 'VariableDeclarator') {
108
+ // When variable is not in the file or coming from import
109
+ this.context.report({
110
+ node: sourceIdentifier,
111
+ messageId: 'cssInModule'
112
+ });
113
+ return;
114
+ }
115
+ if (identifier.parent.parent.parent.type !== 'Program') {
116
+ // When variable is declared inside the component
117
+ this.context.report({
118
+ node: sourceIdentifier,
119
+ messageId: this.configuration.stylesPlacement === 'bottom' ? 'cssAtBottomOfModule' : 'cssAtTopOfModule',
120
+ fix: function fix(fixer) {
121
+ if (_this.configuration.fixNamesOnly) {
122
+ return [];
123
+ }
124
+ return _this.fixCssNotInModuleScope(fixer, identifier, false);
118
125
  }
119
- return addCssFunctionCall(fixer, context, identifier.parent, configuration, cssAttributeName);
126
+ });
127
+ return;
128
+ }
129
+ if (identifier.parent && identifier.parent.init && !isCssCallExpression(identifier.parent.init, this.configuration.cssFunctions)) {
130
+ // When variable value is not of type css({})
131
+ var value = identifier.parent.init;
132
+ if (!value) {
133
+ return;
120
134
  }
121
- });
122
- } else {
123
- context.report({
124
- node: identifier,
125
- messageId: 'cssObjectTypeOnly'
126
- });
135
+ var valueExpression =
136
+ // @ts-expect-error remove once eslint types are switched to @typescript-eslint
137
+ value.type === 'TSAsExpression' ? value.expression : value;
138
+ if (['ObjectExpression', 'TemplateLiteral'].includes(valueExpression.type)) {
139
+ this.context.report({
140
+ node: identifier,
141
+ messageId: 'cssObjectTypeOnly',
142
+ fix: function fix(fixer) {
143
+ if (_this.configuration.fixNamesOnly) {
144
+ return [];
145
+ }
146
+ return _this.addCssFunctionCall(fixer, identifier.parent);
147
+ }
148
+ });
149
+ } else {
150
+ this.context.report({
151
+ node: identifier,
152
+ messageId: 'cssObjectTypeOnly'
153
+ });
154
+ }
155
+ return;
156
+ }
157
+ var spreadProperties = isNodeOfType(identifier.parent.init, 'CallExpression') && findSpreadProperties(identifier.parent.init.arguments[0]);
158
+ if (spreadProperties) {
159
+ // TODO: Recursively handle spread items in children properties.
160
+ spreadProperties.forEach(function (prop) {
161
+ _this.context.report({
162
+ node: prop,
163
+ messageId: 'cssArrayStylesOnly'
164
+ });
165
+ });
166
+ }
127
167
  }
128
- return;
129
- }
130
- var spreadProperties = isNodeOfType(identifier.parent.init, 'CallExpression') && findSpreadProperties(identifier.parent.init.arguments[0]);
131
- if (spreadProperties) {
132
- // TODO: Recursively handle spread items in children properties.
133
- spreadProperties.forEach(function (prop) {
134
- context.report({
135
- node: prop,
136
- messageId: 'cssArrayStylesOnly'
137
- });
138
- });
139
- }
140
- }
141
168
 
142
- /**
143
- * Returns a fixer that adds `import { css } from 'import-source'` or
144
- * `import { xcss } from 'import-source'` to the start of the file, depending
145
- * on the value of cssAttributeName and importSource.
146
- */
147
- var addImportSource = function addImportSource(context, fixer, configuration, cssAttributeName) {
148
- var importSource = cssAttributeName === 'xcss' ? configuration.xcssImportSource : configuration.cssImportSource;
169
+ /**
170
+ * Returns a fixer that adds `import { css } from 'import-source'` or
171
+ * `import { xcss } from 'import-source'` to the start of the file, depending
172
+ * on the value of cssAttributeName and importSource.
173
+ */
174
+ }, {
175
+ key: "addImportSource",
176
+ value: function addImportSource(fixer) {
177
+ var importSource = this.cssAttributeName === 'xcss' ? this.configuration.xcssImportSource : this.configuration.cssImportSource;
149
178
 
150
- // Add the `import { css } from 'my-css-in-js-library';` statement
151
- var packageImport = getFirstSupportedImport(context, [importSource]);
152
- if (packageImport) {
153
- var addCssImport = Import.insertNamedSpecifiers(packageImport, [cssAttributeName], fixer);
154
- if (addCssImport) {
155
- return addCssImport;
179
+ // Add the `import { css } from 'my-css-in-js-library';` statement
180
+ var packageImport = getFirstSupportedImport(this.context, [importSource]);
181
+ if (packageImport) {
182
+ var addCssImport = Import.insertNamedSpecifiers(packageImport, [this.cssAttributeName], fixer);
183
+ if (addCssImport) {
184
+ return addCssImport;
185
+ }
186
+ } else {
187
+ return insertAtStartOfFile(fixer, "".concat(insertImportDeclaration(importSource, [this.cssAttributeName]), ";\n"));
188
+ }
156
189
  }
157
- } else {
158
- return insertAtStartOfFile(fixer, "".concat(insertImportDeclaration(importSource, [cssAttributeName]), ";\n"));
159
- }
160
- };
161
-
162
- /**
163
- * Returns a list of fixes that:
164
- * - add the `css` or `xcss` function call around the current node.
165
- * - add an import statement for the package from which `css` is imported
166
- */
167
- var addCssFunctionCall = function addCssFunctionCall(fixer, context, node, configuration, cssAttributeName) {
168
- var fixes = [];
169
- var sourceCode = context.getSourceCode();
170
- if (node.type !== 'VariableDeclarator' || !node.init || !cssAttributeName) {
171
- return [];
172
- }
173
- var compiledImportFix = addImportSource(context, fixer, configuration, cssAttributeName);
174
- if (compiledImportFix) {
175
- fixes.push(compiledImportFix);
176
- }
177
- var init = node.init;
178
- var initString = sourceCode.getText(init);
179
- if (node.init.type === 'TemplateLiteral') {
180
- fixes.push(fixer.replaceText(init, "".concat(cssAttributeName).concat(initString)));
181
- } else {
182
- fixes.push(fixer.replaceText(init, "".concat(cssAttributeName, "(").concat(initString, ")")));
183
- }
184
- return fixes;
185
- };
186
190
 
187
- /**
188
- * Check if the expression has or potentially has a local variable
189
- * (as opposed to an imported one), erring on the side ot "yes"
190
- * when an expression is too complicated to analyse.
191
- *
192
- * This is useful because expressions containing local variables
193
- * cannot be easily hoisted, whereas this is not a problem with imported
194
- * variables.
195
- *
196
- * @param context Context of the rule.
197
- * @param node Any node that is potentially hoistable.
198
- * @returns Whether the node potentially has a local variable (and thus is not safe to hoist).
199
- */
200
- var potentiallyHasLocalVariable = function potentiallyHasLocalVariable(context, node) {
201
- var hasPotentiallyLocalVariable = false;
202
- var isImportedVariable = function isImportedVariable(identifier) {
203
- return !!getModuleOfIdentifier(context.getSourceCode(), identifier);
204
- };
205
- estraverse.traverse(node, {
206
- enter: function enter(node, _parent) {
207
- if (isNodeOfType(node, 'SpreadElement') ||
208
- // @ts-expect-error remove once we can be sure that no parser interprets
209
- // the spread operator as ExperimentalSpreadProperty anymore
210
- isNodeOfType(node, 'ExperimentalSpreadProperty')) {
211
- // Spread elements could contain anything... so we don't bother.
212
- //
213
- // e.g. <div css={css({ ...(!height && { visibility: 'hidden' })} />
214
- hasPotentiallyLocalVariable = true;
215
- this.break();
191
+ /**
192
+ * Returns a list of fixes that:
193
+ * - add the `css` or `xcss` function call around the current node.
194
+ * - add an import statement for the package from which `css` is imported
195
+ */
196
+ }, {
197
+ key: "addCssFunctionCall",
198
+ value: function addCssFunctionCall(fixer, node) {
199
+ var fixes = [];
200
+ var sourceCode = this.context.getSourceCode();
201
+ if (node.type !== 'VariableDeclarator' || !node.init || !this.cssAttributeName) {
202
+ return [];
216
203
  }
217
- if (!isNodeOfType(node, 'Property')) {
218
- return;
204
+ var compiledImportFix = this.addImportSource(fixer);
205
+ if (compiledImportFix) {
206
+ fixes.push(compiledImportFix);
219
207
  }
220
- switch (node.value.type) {
221
- case 'Literal':
222
- break;
223
- case 'Identifier':
224
- // e.g. css({ margin: myVariable })
225
- if (!isImportedVariable(node.value.name)) {
208
+ var init = node.init;
209
+ var initString = sourceCode.getText(init);
210
+ if (node.init.type === 'TemplateLiteral') {
211
+ fixes.push(fixer.replaceText(init, "".concat(this.cssAttributeName).concat(initString)));
212
+ } else {
213
+ fixes.push(fixer.replaceText(init, "".concat(this.cssAttributeName, "(").concat(initString, ")")));
214
+ }
215
+ return fixes;
216
+ }
217
+
218
+ /**
219
+ * Check if the expression has or potentially has a local variable
220
+ * (as opposed to an imported one), erring on the side ot "yes"
221
+ * when an expression is too complicated to analyse.
222
+ *
223
+ * This is useful because expressions containing local variables
224
+ * cannot be easily hoisted, whereas this is not a problem with imported
225
+ * variables.
226
+ *
227
+ * @param context Context of the rule.
228
+ * @param node Any node that is potentially hoistable.
229
+ * @returns Whether the node potentially has a local variable (and thus is not safe to hoist).
230
+ */
231
+ }, {
232
+ key: "potentiallyHasLocalVariable",
233
+ value: function potentiallyHasLocalVariable(node) {
234
+ var _this2 = this;
235
+ var hasPotentiallyLocalVariable = false;
236
+ var isImportedVariable = function isImportedVariable(identifier) {
237
+ return !!getModuleOfIdentifier(_this2.context.getSourceCode(), identifier);
238
+ };
239
+ estraverse.traverse(node, {
240
+ enter: function enter(node, _parent) {
241
+ if (isNodeOfType(node, 'SpreadElement') ||
242
+ // @ts-expect-error remove once we can be sure that no parser interprets
243
+ // the spread operator as ExperimentalSpreadProperty anymore
244
+ isNodeOfType(node, 'ExperimentalSpreadProperty')) {
245
+ // Spread elements could contain anything... so we don't bother.
246
+ //
247
+ // e.g. <div css={css({ ...(!height && { visibility: 'hidden' })} />
226
248
  hasPotentiallyLocalVariable = true;
249
+ this.break();
227
250
  }
228
- this.break();
229
- break;
230
- case 'MemberExpression':
231
- // e.g. css({ margin: props.color })
232
- // css({ margin: props.media.color })
233
- if (node.value.object.type === 'Identifier' && isImportedVariable(node.value.object.name)) {
234
- // We found an imported variable, don't do anything.
235
- } else {
236
- // e.g. css({ margin: [some complicated expression].media.color })
237
- // This can potentially get too complex, so we assume there's a local
238
- // variable in there somewhere.
239
- hasPotentiallyLocalVariable = true;
251
+ if (!isNodeOfType(node, 'Property')) {
252
+ return;
240
253
  }
241
- this.break();
242
- break;
243
- case 'TemplateLiteral':
244
- if (!!node.value.expressions.length) {
245
- // Too many edge cases here, don't bother...
246
- // e.g. css({ animation: `${expandStyles(right, rightExpanded, isExpanded)} 0.2s ease-in-out` });
247
- hasPotentiallyLocalVariable = true;
248
- this.break();
254
+ switch (node.value.type) {
255
+ case 'Literal':
256
+ break;
257
+ case 'Identifier':
258
+ // e.g. css({ margin: myVariable })
259
+ if (!isImportedVariable(node.value.name)) {
260
+ hasPotentiallyLocalVariable = true;
261
+ }
262
+ this.break();
263
+ break;
264
+ case 'MemberExpression':
265
+ // e.g. css({ margin: props.color })
266
+ // css({ margin: props.media.color })
267
+ if (node.value.object.type === 'Identifier' && isImportedVariable(node.value.object.name)) {
268
+ // We found an imported variable, don't do anything.
269
+ } else {
270
+ // e.g. css({ margin: [some complicated expression].media.color })
271
+ // This can potentially get too complex, so we assume there's a local
272
+ // variable in there somewhere.
273
+ hasPotentiallyLocalVariable = true;
274
+ }
275
+ this.break();
276
+ break;
277
+ case 'TemplateLiteral':
278
+ if (!!node.value.expressions.length) {
279
+ // Too many edge cases here, don't bother...
280
+ // e.g. css({ animation: `${expandStyles(right, rightExpanded, isExpanded)} 0.2s ease-in-out` });
281
+ hasPotentiallyLocalVariable = true;
282
+ this.break();
283
+ }
284
+ break;
285
+ default:
286
+ // Catch-all for values such as "A && B", "A ? B : C"
287
+ hasPotentiallyLocalVariable = true;
288
+ this.break();
289
+ break;
249
290
  }
250
- break;
251
- default:
252
- // Catch-all for values such as "A && B", "A ? B : C"
253
- hasPotentiallyLocalVariable = true;
254
- this.break();
255
- break;
256
- }
291
+ }
292
+ });
293
+ return hasPotentiallyLocalVariable;
257
294
  }
258
- });
259
- return hasPotentiallyLocalVariable;
260
- };
261
295
 
262
- /**
263
- * Fixer for the cssAtTopOfModule/cssAtBottomOfModule violation cases.
264
- * This deals with Identifiers and Expressions passed from the traverseExpressionWithConfig() function.
265
- *
266
- * @param fixer The ESLint RuleFixer object
267
- * @param context The context of the rule
268
- * @param configuration The configuration of the rule, determining whether the fix is implmeneted at the top or bottom of the module
269
- * @param node Any potentially hoistable node, or an identifier.
270
- * @param cssAttributeName An optional parameter only added when we fix an ObjectExpression
271
- */
272
- var fixCssNotInModuleScope = function fixCssNotInModuleScope(fixer, context, configuration, node, cssAttributeName) {
273
- var sourceCode = context.getSourceCode();
296
+ /**
297
+ * Fixer for the cssAtTopOfModule/cssAtBottomOfModule violation cases.
298
+ *
299
+ * This deals with Identifiers and Expressions passed from the traverseExpressionWithConfig() function.
300
+ *
301
+ * @param fixer The ESLint RuleFixer object
302
+ * @param context The context of the rule
303
+ * @param configuration The configuration of the rule, determining whether the fix is implmeneted at the top or bottom of the module
304
+ * @param node Any potentially hoistable node, or an identifier.
305
+ * @param cssAttributeName An optional parameter only added when we fix an ObjectExpression
306
+ */
307
+ }, {
308
+ key: "fixCssNotInModuleScope",
309
+ value: function fixCssNotInModuleScope(fixer, node, isObjectExpression) {
310
+ var sourceCode = this.context.getSourceCode();
274
311
 
275
- // Get the program node in order to properly position the hoisted styles
276
- var programNode = getProgramNode(node);
277
- var fixerNodePlacement = programNode;
278
- if (configuration.stylesPlacement === 'bottom') {
279
- // The last value is the bottom of the file
280
- fixerNodePlacement = programNode.body[programNode.body.length - 1];
281
- } else {
282
- // Place after the last ImportDeclaration
283
- fixerNodePlacement = programNode.body.length === 1 ? programNode.body[0] : programNode.body.find(function (node) {
284
- return node.type !== 'ImportDeclaration';
285
- });
286
- }
287
- var moduleString;
288
- var fixes = [];
289
- if (node.type === 'Identifier') {
290
- var identifier = node;
291
- var declarator = identifier.parent.parent;
292
- moduleString = sourceCode.getText(declarator);
293
- fixes.push(fixer.remove(declarator));
294
- } else {
295
- if (potentiallyHasLocalVariable(context, node)) {
296
- return [];
297
- }
298
- var _declarator = getDeclaratorString(context);
299
- var text = sourceCode.getText(node);
312
+ // Get the program node in order to properly position the hoisted styles
313
+ var programNode = getProgramNode(node);
314
+ var fixerNodePlacement = programNode;
315
+ if (this.configuration.stylesPlacement === 'bottom') {
316
+ // The last value is the bottom of the file
317
+ fixerNodePlacement = programNode.body[programNode.body.length - 1];
318
+ } else {
319
+ // Place after the last ImportDeclaration
320
+ fixerNodePlacement = programNode.body.length === 1 ? programNode.body[0] : programNode.body.find(function (node) {
321
+ return node.type !== 'ImportDeclaration';
322
+ });
323
+ }
324
+ var moduleString;
325
+ var fixes = [];
326
+ if (node.type === 'Identifier') {
327
+ var identifier = node;
328
+ var declarator = identifier.parent.parent;
329
+ moduleString = sourceCode.getText(declarator);
330
+ fixes.push(fixer.remove(declarator));
331
+ } else {
332
+ if (this.potentiallyHasLocalVariable(node)) {
333
+ return [];
334
+ }
335
+ var _declarator = this.getDeclaratorString();
336
+ var text = sourceCode.getText(node);
300
337
 
301
- // If this has been passed, then we know it's an ObjectExpression
302
- if (cssAttributeName) {
303
- moduleString = "const ".concat(_declarator, " = ").concat(cssAttributeName, "(").concat(text, ");");
304
- var compiledImportFix = addImportSource(context, fixer, configuration, cssAttributeName);
305
- if (compiledImportFix) {
306
- fixes.push(compiledImportFix);
338
+ // If this has been passed, then we know it's an ObjectExpression
339
+ if (isObjectExpression) {
340
+ moduleString = "const ".concat(_declarator, " = ").concat(this.cssAttributeName, "(").concat(text, ");");
341
+ var compiledImportFix = this.addImportSource(fixer);
342
+ if (compiledImportFix) {
343
+ fixes.push(compiledImportFix);
344
+ }
345
+ } else {
346
+ moduleString = "const ".concat(_declarator, " = ").concat(text, ";");
347
+ }
348
+ fixes.push(fixer.replaceText(node, _declarator));
307
349
  }
308
- } else {
309
- moduleString = "const ".concat(_declarator, " = ").concat(text, ";");
350
+ return [].concat(fixes, [
351
+ // Insert the node either before or after, depending on the rule configuration
352
+ this.configuration.stylesPlacement === 'bottom' ? fixer.insertTextAfter(fixerNodePlacement, '\n' + moduleString) : fixer.insertTextBefore(fixerNodePlacement, moduleString + '\n')]);
310
353
  }
311
- fixes.push(fixer.replaceText(node, _declarator));
312
- }
313
- return [].concat(fixes, [
314
- // Insert the node either before or after, depending on the rule configuration
315
- configuration.stylesPlacement === 'bottom' ? fixer.insertTextAfter(fixerNodePlacement, '\n' + moduleString) : fixer.insertTextBefore(fixerNodePlacement, moduleString + '\n')]);
316
- };
317
354
 
318
- /**
319
- * Handle different cases based on what's been passed in the css-related JSXAttribute
320
- * @param context the context of the rule
321
- * @param expression the expression of the JSXAttribute value
322
- * @param configuration what css-related functions to account for (eg. css, xcss, cssMap), and whether to detect bottom vs top expressions
323
- * @param cssAttributeName used to encapsulate ObjectExpressions when cssAtTopOfModule/cssAtBottomOfModule violations are triggered
324
- */
325
- var traverseExpressionWithConfig = function traverseExpressionWithConfig(context, expression, configuration, cssAttributeName) {
326
- function traverseExpression(expression) {
327
- switch (expression.type) {
328
- case 'Identifier':
329
- // {styles}
330
- // We've found an identifier - time to analyze it!
331
- analyzeIdentifier(context, expression, configuration, cssAttributeName);
332
- break;
333
- case 'ArrayExpression':
334
- // {[styles, moreStyles]}
335
- // We've found an array expression - let's traverse again over each element individually.
336
- expression.elements.forEach(function (element) {
337
- return traverseExpression(element);
338
- });
339
- break;
340
- case 'LogicalExpression':
341
- // {isEnabled && styles}
342
- // We've found a logical expression - we're only interested in the right expression so
343
- // let's traverse that and see what it is!
344
- traverseExpression(expression.right);
345
- break;
346
- case 'ConditionalExpression':
347
- // {isEnabled ? styles : null}
348
- // We've found a conditional expression - we're only interested in the consequent and
349
- // alternate (styles : null)
350
- traverseExpression(expression.consequent);
351
- traverseExpression(expression.alternate);
352
- break;
353
- case 'ObjectExpression':
354
- case 'CallExpression':
355
- case 'TaggedTemplateExpression':
356
- case 'TemplateLiteral':
357
- // We've found elements that shouldn't be here! Report an error.
358
- context.report({
359
- node: expression,
360
- messageId: configuration.stylesPlacement === 'bottom' ? 'cssAtBottomOfModule' : 'cssAtTopOfModule',
361
- fix: function fix(fixer) {
362
- if (configuration.fixNamesOnly) {
363
- return [];
364
- }
355
+ /**
356
+ * Handle different cases based on what's been passed in the css-related JSXAttribute.
357
+ *
358
+ * @param expression the expression of the JSXAttribute value.
359
+ */
360
+ }, {
361
+ key: "traverseExpression",
362
+ value: function traverseExpression(expression) {
363
+ var _this3 = this;
364
+ switch (expression.type) {
365
+ case 'Identifier':
366
+ // {styles}
367
+ // We've found an identifier - time to analyze it!
368
+ this.analyzeIdentifier(expression);
369
+ break;
370
+ case 'ArrayExpression':
371
+ // {[styles, moreStyles]}
372
+ // We've found an array expression - let's traverse again over each element individually.
373
+ expression.elements.forEach(function (element) {
374
+ return _this3.traverseExpression(element);
375
+ });
376
+ break;
377
+ case 'LogicalExpression':
378
+ // {isEnabled && styles}
379
+ // We've found a logical expression - we're only interested in the right expression so
380
+ // let's traverse that and see what it is!
381
+ this.traverseExpression(expression.right);
382
+ break;
383
+ case 'ConditionalExpression':
384
+ // {isEnabled ? styles : null}
385
+ // We've found a conditional expression - we're only interested in the consequent and
386
+ // alternate (styles : null)
387
+ this.traverseExpression(expression.consequent);
388
+ this.traverseExpression(expression.alternate);
389
+ break;
390
+ case 'ObjectExpression':
391
+ case 'CallExpression':
392
+ case 'TaggedTemplateExpression':
393
+ case 'TemplateLiteral':
394
+ // We've found elements that shouldn't be here! Report an error.
395
+ this.context.report({
396
+ node: expression,
397
+ messageId: this.configuration.stylesPlacement === 'bottom' ? 'cssAtBottomOfModule' : 'cssAtTopOfModule',
398
+ fix: function fix(fixer) {
399
+ if (_this3.configuration.fixNamesOnly) {
400
+ return [];
401
+ }
365
402
 
366
- // Don't fix CallExpressions unless they're from cssFunctions or cssMap
367
- if (expression.type === 'CallExpression' && !isCssCallExpression(expression, configuration.cssFunctions)) {
368
- return [];
403
+ // Don't fix CallExpressions unless they're from cssFunctions or cssMap
404
+ if (expression.type === 'CallExpression' && !isCssCallExpression(expression, _this3.configuration.cssFunctions)) {
405
+ return [];
406
+ }
407
+ if (expression.type === 'ObjectExpression') {
408
+ return _this3.fixCssNotInModuleScope(fixer, expression, true);
409
+ }
410
+ return _this3.fixCssNotInModuleScope(fixer, expression, false);
369
411
  }
370
- if (expression.type === 'ObjectExpression') {
371
- return fixCssNotInModuleScope(fixer, context, configuration, expression, cssAttributeName);
372
- }
373
- return fixCssNotInModuleScope(fixer, context, configuration, expression);
374
- }
375
- });
376
- break;
412
+ });
413
+ break;
377
414
 
378
- // @ts-expect-error - our ESLint-related types assume vanilla JS, when in fact
379
- // it is running @typescript-eslint
380
- //
381
- // Switching to the more accurate @typescript-eslint types would break
382
- // eslint-codemod-utils and all ESLint rules in packages/design-system,
383
- // so we just leave this as-is.
384
- case 'TSAsExpression':
385
- // @ts-expect-error
386
- traverseExpression(expression.expression);
387
- break;
388
- default:
389
- // Do nothing!
390
- break;
415
+ // @ts-expect-error - our ESLint-related types assume vanilla JS, when in fact
416
+ // it is running @typescript-eslint
417
+ //
418
+ // Switching to the more accurate @typescript-eslint types would break
419
+ // eslint-codemod-utils and all ESLint rules in packages/design-system,
420
+ // so we just leave this as-is.
421
+ case 'TSAsExpression':
422
+ // @ts-expect-error
423
+ this.traverseExpression(expression.expression);
424
+ break;
425
+ default:
426
+ // Do nothing!
427
+ break;
428
+ }
391
429
  }
392
- }
393
- traverseExpression(expression);
394
- };
430
+ }, {
431
+ key: "run",
432
+ value: function run() {
433
+ return this.traverseExpression(this.expression);
434
+ }
435
+ }]);
436
+ return JSXExpressionLinter;
437
+ }();
395
438
  var defaultConfig = {
396
439
  cssFunctions: ['css', 'xcss'],
397
440
  stylesPlacement: 'top',
@@ -503,9 +546,6 @@ var rule = createLintRule({
503
546
  return;
504
547
  }
505
548
  }
506
-
507
- // Always reset to empty array
508
- hoistedCss = [];
509
549
  if (name.type === 'JSXIdentifier' && mergedConfig.cssFunctions.includes(name.name)) {
510
550
  // When not a jsx expression. For eg. css=""
511
551
  if ((value === null || value === void 0 ? void 0 : value.type) !== 'JSXExpressionContainer') {
@@ -520,7 +560,8 @@ var rule = createLintRule({
520
560
  // <div css={/* Hello there */} />
521
561
  return;
522
562
  }
523
- traverseExpressionWithConfig(context, value.expression, mergedConfig, name.name);
563
+ var linter = new JSXExpressionLinter(context, name.name, mergedConfig, value.expression);
564
+ linter.run();
524
565
  }
525
566
  }), _ref3;
526
567
  }