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