@agilebot/eslint-plugin 0.3.5 → 0.3.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license @agilebot/eslint-plugin v0.3.5
2
+ * @license @agilebot/eslint-plugin v0.3.7
3
3
  *
4
4
  * Copyright (c) Agilebot, Inc. and its affiliates.
5
5
  *
@@ -33,7 +33,7 @@ function _interopNamespaceDefault(e) {
33
33
  var fs__namespace = /*#__PURE__*/_interopNamespaceDefault(fs);
34
34
  var path__namespace = /*#__PURE__*/_interopNamespaceDefault(path);
35
35
 
36
- var enforceIconAlias = {
36
+ var enforceMuiIconAlias = {
37
37
  meta: {
38
38
  type: 'problem',
39
39
  docs: {
@@ -49,10 +49,7 @@ var enforceIconAlias = {
49
49
  create(context) {
50
50
  return {
51
51
  ImportDeclaration(node) {
52
- if (
53
- node.source.value !== '@mui/icons-material' &&
54
- node.source.value !== 'mdi-material-ui'
55
- ) {
52
+ if (node.source.value !== '@mui/icons-material' && node.source.value !== 'mdi-material-ui') {
56
53
  return;
57
54
  }
58
55
  for (const specifier of node.specifiers) {
@@ -66,11 +63,7 @@ var enforceIconAlias = {
66
63
  data: {
67
64
  name: node.source.value
68
65
  },
69
- fix: fixer =>
70
- fixer.replaceText(
71
- specifier,
72
- `${specifier.imported.name} as ${specifier.imported.name}Icon`
73
- )
66
+ fix: fixer => fixer.replaceText(specifier, "".concat(specifier.imported.name, " as ").concat(specifier.imported.name, "Icon"))
74
67
  });
75
68
  }
76
69
  }
@@ -80,11 +73,19 @@ var enforceIconAlias = {
80
73
  };
81
74
 
82
75
  function getSetting(context, name) {
83
- return context.settings[`agilebot/${name}`];
76
+ return context.settings["agilebot/".concat(name)];
84
77
  }
85
78
 
86
- let warnedForMissingPrefix = false;
87
- var monorepo = {
79
+ const warned = new Set();
80
+ function warnOnce(message) {
81
+ if (warned.has(message)) {
82
+ return;
83
+ }
84
+ warned.add(message);
85
+ console.warn("Warning: ".concat(message));
86
+ }
87
+
88
+ var importMonorepo = {
88
89
  meta: {
89
90
  type: 'problem',
90
91
  docs: {
@@ -102,13 +103,10 @@ var monorepo = {
102
103
  ImportDeclaration(node) {
103
104
  let prefix = getSetting(context, 'monorepo-scope');
104
105
  if (!prefix) {
105
- if (!warnedForMissingPrefix) {
106
- console.error('Warning: agilebot/monorepo-scope is not set.');
107
- warnedForMissingPrefix = true;
108
- }
106
+ warnOnce('agilebot/monorepo-scope is not set.');
109
107
  return;
110
108
  }
111
- prefix = `${prefix}/`;
109
+ prefix = "".concat(prefix, "/");
112
110
  if (typeof node.source.value !== 'string') {
113
111
  return;
114
112
  }
@@ -124,10 +122,8 @@ var monorepo = {
124
122
  module: node.source.value
125
123
  },
126
124
  fix: fixer => {
127
- const correctedPath = values
128
- .filter((_, index) => index !== 2)
129
- .join('/');
130
- return fixer.replaceText(node.source, `'${correctedPath}'`);
125
+ const correctedPath = values.filter((_, index) => index !== 2).join('/');
126
+ return fixer.replaceText(node.source, "'".concat(correctedPath, "'"));
131
127
  }
132
128
  });
133
129
  }
@@ -137,74 +133,33 @@ var monorepo = {
137
133
  };
138
134
 
139
135
  function findFormatMessageAttrNode(node, attrName) {
140
- if (
141
- node.type === 'CallExpression' &&
142
- (node.callee.name === 'formatMessage' || node.callee.name === '$t') &&
143
- node.arguments.length > 0 &&
144
- node.arguments[0].properties
145
- ) {
146
- return node.arguments[0].properties.find(
147
- a => a.key && a.key.name === attrName
148
- );
136
+ if (node.type === 'CallExpression' && (node.callee.name === 'formatMessage' || node.callee.name === '$t') && node.arguments.length > 0 && node.arguments[0].properties) {
137
+ return node.arguments[0].properties.find(a => a.key && a.key.name === attrName);
149
138
  }
150
- if (
151
- node.type === 'CallExpression' &&
152
- node.callee.type === 'MemberExpression' &&
153
- (node.callee.object.name === 'intl' ||
154
- (node.callee.object.name && node.callee.object.name.endsWith('Intl'))) &&
155
- (node.callee.property.name === 'formatMessage' ||
156
- node.callee.property.name === '$t')
157
- ) {
158
- return node.arguments[0].properties.find(
159
- a => a.key && a.key.name === attrName
160
- );
139
+ if (node.type === 'CallExpression' && node.callee.type === 'MemberExpression' && (node.callee.object.name === 'intl' || node.callee.object.name && node.callee.object.name.endsWith('Intl')) && (node.callee.property.name === 'formatMessage' || node.callee.property.name === '$t')) {
140
+ return node.arguments[0].properties.find(a => a.key && a.key.name === attrName);
161
141
  }
162
142
  }
163
143
  function findFormattedMessageAttrNode(node, attrName) {
164
- if (
165
- node.type === 'JSXIdentifier' &&
166
- node.name === 'FormattedMessage' &&
167
- node.parent &&
168
- node.parent.type === 'JSXOpeningElement'
169
- ) {
144
+ if (node.type === 'JSXIdentifier' && node.name === 'FormattedMessage' && node.parent && node.parent.type === 'JSXOpeningElement') {
170
145
  return node.parent.attributes.find(a => a.name && a.name.name === attrName);
171
146
  }
172
147
  }
173
148
  function findAttrNodeInDefineMessages(node, attrName) {
174
- if (
175
- node.type === 'Property' &&
176
- node.key.name === attrName &&
177
- node.parent &&
178
- node.parent.parent &&
179
- node.parent.parent.parent &&
180
- node.parent.parent.parent.parent &&
181
- node.parent.parent.parent.parent.type === 'CallExpression' &&
182
- node.parent.parent.parent.parent.callee.name === 'defineMessages'
183
- ) {
149
+ if (node.type === 'Property' && node.key.name === attrName && node.parent && node.parent.parent && node.parent.parent.parent && node.parent.parent.parent.parent && node.parent.parent.parent.parent.type === 'CallExpression' && node.parent.parent.parent.parent.callee.name === 'defineMessages') {
184
150
  return node;
185
151
  }
186
152
  }
187
153
  function findAttrNodeInDefineMessage(node, attrName) {
188
- if (
189
- node.type === 'Property' &&
190
- node.key.name === attrName &&
191
- node.parent &&
192
- node.parent.parent &&
193
- node.parent.parent.type === 'CallExpression' &&
194
- node.parent.parent.callee.name === 'defineMessage'
195
- ) {
154
+ if (node.type === 'Property' && node.key.name === attrName && node.parent && node.parent.parent && node.parent.parent.type === 'CallExpression' && node.parent.parent.callee.name === 'defineMessage') {
196
155
  return node;
197
156
  }
198
157
  }
199
158
  function sortedTemplateElements(node) {
200
- return [...node.quasis, ...node.expressions].sort(
201
- (a, b) => a.range[0] - b.range[0]
202
- );
159
+ return [...node.quasis, ...node.expressions].sort((a, b) => a.range[0] - b.range[0]);
203
160
  }
204
161
  function templateLiteralDisplayStr(node) {
205
- return sortedTemplateElements(node)
206
- .map(e => (!e.value ? '*' : e.value.raw))
207
- .join('');
162
+ return sortedTemplateElements(node).map(e => !e.value ? '*' : e.value.raw).join('');
208
163
  }
209
164
 
210
165
  const localeFilesKeys = {};
@@ -218,22 +173,19 @@ function getIntlIds(context) {
218
173
  localeFiles.forEach(f => {
219
174
  const fullPath = projectRoot ? path__namespace.join(projectRoot, f) : f;
220
175
  const mtime = fs__namespace.lstatSync(fullPath).mtime.getTime();
221
- if (
222
- !localeFilesKeys[fullPath] ||
223
- mtime !== localeFilesKeys[fullPath].mtime
224
- ) {
176
+ if (!localeFilesKeys[fullPath] || mtime !== localeFilesKeys[fullPath].mtime) {
225
177
  let json;
226
178
  if (fullPath.endsWith('.json')) {
227
179
  json = JSON.parse(fs__namespace.readFileSync(fullPath, 'utf8'));
228
180
  } else if (fullPath.endsWith('.ts')) {
229
181
  json = eslintUtils.tsImport(fullPath);
230
- if (typeof json === 'object' && json.default) {
231
- json = json.default;
182
+ if (typeof json === 'object' && json["default"]) {
183
+ json = json["default"];
232
184
  }
233
185
  } else if (fullPath.endsWith('.js')) {
234
186
  json = require(fullPath);
235
- if (typeof json === 'object' && json.default) {
236
- json = json.default;
187
+ if (typeof json === 'object' && json["default"]) {
188
+ json = json["default"];
237
189
  }
238
190
  } else {
239
191
  throw new Error('unsupported file extension');
@@ -248,7 +200,7 @@ function getIntlIds(context) {
248
200
  return results;
249
201
  }
250
202
 
251
- var idMissing = {
203
+ var intlIdMissing = {
252
204
  meta: {
253
205
  docs: {
254
206
  description: 'Validates intl message ids are in locale file',
@@ -275,9 +227,7 @@ var idMissing = {
275
227
  }
276
228
  }
277
229
  function processTemplateLiteral(node) {
278
- const exStr = sortedTemplateElements(node)
279
- .map(e => (!e.value ? '.*' : e.value.raw))
280
- .join('');
230
+ const exStr = sortedTemplateElements(node).map(e => !e.value ? '.*' : e.value.raw).join('');
281
231
  const re = new RegExp(exStr);
282
232
  if (!isTemplateTranslated(re)) {
283
233
  context.report({
@@ -290,10 +240,7 @@ var idMissing = {
290
240
  if (node.value.type === 'Literal') {
291
241
  return processLiteral(node.value);
292
242
  }
293
- if (
294
- node.value.type === 'JSXExpressionContainer' &&
295
- node.value.expression.type === 'TemplateLiteral'
296
- ) {
243
+ if (node.value.type === 'JSXExpressionContainer' && node.value.expression.type === 'TemplateLiteral') {
297
244
  return processTemplateLiteral(node.value.expression);
298
245
  }
299
246
  if (node.value.type === 'TemplateLiteral') {
@@ -318,9 +265,7 @@ var idMissing = {
318
265
  }
319
266
  },
320
267
  Property: function (node) {
321
- const attrNode =
322
- findAttrNodeInDefineMessages(node, 'id') ||
323
- findAttrNodeInDefineMessage(node, 'id');
268
+ const attrNode = findAttrNodeInDefineMessages(node, 'id') || findAttrNodeInDefineMessage(node, 'id');
324
269
  if (attrNode) {
325
270
  return processAttrNode(attrNode);
326
271
  }
@@ -329,33 +274,122 @@ var idMissing = {
329
274
  }
330
275
  };
331
276
 
332
- var idPrefix = {
277
+ var intlIdNaming = {
333
278
  meta: {
334
279
  docs: {
335
- description: 'Validates intl message ids has correct prefixes',
280
+ description: 'Validates intl message ids naming convention',
336
281
  category: 'Intl'
337
282
  },
338
283
  fixable: undefined,
339
- schema: [
340
- {
341
- type: 'array',
342
- items: {
343
- type: 'string'
284
+ schema: [{
285
+ type: 'object',
286
+ properties: {
287
+ format: {
288
+ "enum": ['camelCase', 'PascalCase']
344
289
  }
345
290
  }
346
- ]
291
+ }],
292
+ messages: {
293
+ invalidIdNaming: "Invalid id naming, expected {{format}}"
294
+ }
295
+ },
296
+ create: function (context) {
297
+ if (!context.options[0]) {
298
+ throw new Error('Missing options');
299
+ }
300
+ const format = context.options[0].format;
301
+ function report(node, value) {
302
+ const values = value.split('.');
303
+ let isPass;
304
+ for (const v of values) {
305
+ switch (format) {
306
+ case 'camelCase':
307
+ if (!eslintUtils.isCamelCase(v)) {
308
+ isPass = false;
309
+ }
310
+ break;
311
+ case 'PascalCase':
312
+ if (!eslintUtils.isPascalCase(v)) {
313
+ isPass = false;
314
+ }
315
+ break;
316
+ }
317
+ }
318
+ if (isPass === false) {
319
+ context.report({
320
+ node: node,
321
+ messageId: 'invalidIdNaming',
322
+ data: {
323
+ format
324
+ }
325
+ });
326
+ }
327
+ }
328
+ function processLiteral(node) {
329
+ report(node, node.value);
330
+ }
331
+ function processTemplateLiteral(node) {
332
+ const displayStr = templateLiteralDisplayStr(node);
333
+ report(node, displayStr);
334
+ }
335
+ function processAttrNode(node) {
336
+ if (node.value.type === 'Literal') {
337
+ return processLiteral(node.value);
338
+ }
339
+ if (node.value.type === 'JSXExpressionContainer' && node.value.expression.type === 'TemplateLiteral') {
340
+ return processTemplateLiteral(node.value.expression);
341
+ }
342
+ if (node.value.type === 'TemplateLiteral') {
343
+ return processTemplateLiteral(node.value);
344
+ }
345
+ }
346
+ return {
347
+ JSXIdentifier: function (node) {
348
+ const attrNode = findFormattedMessageAttrNode(node, 'id');
349
+ if (attrNode) {
350
+ return processAttrNode(attrNode);
351
+ }
352
+ },
353
+ CallExpression: function (node) {
354
+ const attrNode = findFormatMessageAttrNode(node, 'id');
355
+ if (attrNode) {
356
+ return processAttrNode(attrNode);
357
+ }
358
+ },
359
+ Property: function (node) {
360
+ const attrNode = findAttrNodeInDefineMessages(node, 'id') || findAttrNodeInDefineMessage(node, 'id');
361
+ if (attrNode) {
362
+ return processAttrNode(attrNode);
363
+ }
364
+ }
365
+ };
366
+ }
367
+ };
368
+
369
+ var intlIdPrefix = {
370
+ meta: {
371
+ docs: {
372
+ description: 'Validates intl message ids has correct prefixes',
373
+ category: 'Intl'
374
+ },
375
+ fixable: undefined,
376
+ schema: [{
377
+ type: 'array',
378
+ items: {
379
+ type: 'string'
380
+ }
381
+ }]
347
382
  },
348
383
  create: function (context) {
349
384
  if (context.options[0].length === 0) {
350
385
  throw new Error('Prefixes are required in settings');
351
386
  }
352
- const hasPrefix = value =>
353
- context.options[0].some(p => value.startsWith(p));
387
+ const hasPrefix = value => context.options[0].some(p => value.startsWith(p));
354
388
  function report(node, value) {
355
389
  if (!hasPrefix(value)) {
356
390
  context.report({
357
391
  node: node,
358
- message: `Invalid id prefix: ${value}`
392
+ message: "Invalid id prefix: ".concat(value)
359
393
  });
360
394
  }
361
395
  }
@@ -370,10 +404,7 @@ var idPrefix = {
370
404
  if (node.value.type === 'Literal') {
371
405
  return processLiteral(node.value);
372
406
  }
373
- if (
374
- node.value.type === 'JSXExpressionContainer' &&
375
- node.value.expression.type === 'TemplateLiteral'
376
- ) {
407
+ if (node.value.type === 'JSXExpressionContainer' && node.value.expression.type === 'TemplateLiteral') {
377
408
  return processTemplateLiteral(node.value.expression);
378
409
  }
379
410
  if (node.value.type === 'TemplateLiteral') {
@@ -394,9 +425,7 @@ var idPrefix = {
394
425
  }
395
426
  },
396
427
  Property: function (node) {
397
- const attrNode =
398
- findAttrNodeInDefineMessages(node, 'id') ||
399
- findAttrNodeInDefineMessage(node, 'id');
428
+ const attrNode = findAttrNodeInDefineMessages(node, 'id') || findAttrNodeInDefineMessage(node, 'id');
400
429
  if (attrNode) {
401
430
  return processAttrNode(attrNode);
402
431
  }
@@ -406,7 +435,7 @@ var idPrefix = {
406
435
  };
407
436
 
408
437
  const usedIds = new Map();
409
- var idUnused = {
438
+ var intlIdUnused = {
410
439
  meta: {
411
440
  docs: {
412
441
  description: 'Finds unused intl message ids in locale file',
@@ -438,9 +467,7 @@ var idUnused = {
438
467
  }
439
468
  }
440
469
  function processTemplateLiteral(node) {
441
- const exStr = sortedTemplateElements(node)
442
- .map(e => (!e.value ? '.*' : e.value.raw))
443
- .join('');
470
+ const exStr = sortedTemplateElements(node).map(e => !e.value ? '.*' : e.value.raw).join('');
444
471
  const re = new RegExp(exStr);
445
472
  if (isTemplateTranslated(re)) ;
446
473
  }
@@ -448,10 +475,7 @@ var idUnused = {
448
475
  if (node.value.type === 'Literal') {
449
476
  return processLiteral(node.value);
450
477
  }
451
- if (
452
- node.value.type === 'JSXExpressionContainer' &&
453
- node.value.expression.type === 'TemplateLiteral'
454
- ) {
478
+ if (node.value.type === 'JSXExpressionContainer' && node.value.expression.type === 'TemplateLiteral') {
455
479
  return processTemplateLiteral(node.value.expression);
456
480
  }
457
481
  if (node.value.type === 'TemplateLiteral') {
@@ -472,9 +496,7 @@ var idUnused = {
472
496
  }
473
497
  },
474
498
  Property: function (node) {
475
- const attrNode =
476
- findAttrNodeInDefineMessages(node, 'id') ||
477
- findAttrNodeInDefineMessage(node, 'id');
499
+ const attrNode = findAttrNodeInDefineMessages(node, 'id') || findAttrNodeInDefineMessage(node, 'id');
478
500
  if (attrNode) {
479
501
  return processAttrNode(attrNode);
480
502
  }
@@ -488,7 +510,7 @@ var idUnused = {
488
510
  }
489
511
  };
490
512
 
491
- var noDefault = {
513
+ var intlNoDefault = {
492
514
  meta: {
493
515
  docs: {
494
516
  description: 'Validates defaultMessage is not used with react-intl',
@@ -518,9 +540,7 @@ var noDefault = {
518
540
  }
519
541
  },
520
542
  Property: function (node) {
521
- const attrNode =
522
- findAttrNodeInDefineMessages(node, 'defaultMessage') ||
523
- findAttrNodeInDefineMessage(node, 'defaultMessage');
543
+ const attrNode = findAttrNodeInDefineMessages(node, 'defaultMessage') || findAttrNodeInDefineMessage(node, 'defaultMessage');
524
544
  if (attrNode) {
525
545
  return processAttrNode(attrNode);
526
546
  }
@@ -529,79 +549,213 @@ var noDefault = {
529
549
  }
530
550
  };
531
551
 
532
- var betterExhaustiveDeps = {
552
+ var noAsyncArrayMethods = {
553
+ meta: {
554
+ docs: {
555
+ description: 'No async callback for Array methods forEach, map, filter, reduce, some, every, etc.',
556
+ category: 'Array',
557
+ recommended: true
558
+ },
559
+ fixable: undefined,
560
+ schema: [],
561
+ messages: {
562
+ noAsyncArrayMethods: "No async function in method '{{ methodName }}'"
563
+ }
564
+ },
565
+ create: function (context) {
566
+ return {
567
+ ExpressionStatement: function (node) {
568
+ const notAllowedArrayMethods = ['forEach', 'filter', 'some', 'every', 'map', 'reduce', 'reduceRight', 'flatMap', 'find', 'findIndex', 'findLast', 'findLastIndex'];
569
+ const {
570
+ callee
571
+ } = node.expression;
572
+ if (!callee || !callee.property || !callee.property.name) {
573
+ return;
574
+ }
575
+ if (notAllowedArrayMethods.includes(callee.property.name)) {
576
+ const functionArguments = node.expression.arguments.find(n => {
577
+ return ['ArrowFunctionExpression', 'FunctionExpression'].includes(n.type);
578
+ });
579
+ if (functionArguments && functionArguments.async) {
580
+ context.report({
581
+ node,
582
+ messageId: 'noAsyncArrayMethods',
583
+ data: {
584
+ methodName: callee.property.name
585
+ }
586
+ });
587
+ }
588
+ }
589
+ }
590
+ };
591
+ }
592
+ };
593
+
594
+ var noImportCss = {
595
+ meta: {
596
+ type: 'problem',
597
+ docs: {
598
+ description: 'Prevent importing CSS',
599
+ recommended: true
600
+ },
601
+ fixable: 'code',
602
+ schema: [],
603
+ messages: {
604
+ noImportCSS: 'Do not import CSS files. Use CSS-in-JS instead.'
605
+ }
606
+ },
607
+ create(context) {
608
+ return {
609
+ ImportDeclaration(node) {
610
+ const ext = path.extname(node.source.value);
611
+ if (ext.startsWith('.css') || ext.startsWith('.scss') || ext.startsWith('.sass') || ext.startsWith('.less') || ext.startsWith('.styl')) {
612
+ context.report({
613
+ node,
614
+ messageId: 'noImportCSS',
615
+ data: {
616
+ path: node.source.value
617
+ }
618
+ });
619
+ }
620
+ }
621
+ };
622
+ }
623
+ };
624
+
625
+ var noThenCatchFinally = {
626
+ meta: {
627
+ type: 'suggestion',
628
+ docs: {
629
+ description: 'Disallow the use of then()/catch()/finally() when invoking specific functions.'
630
+ },
631
+ schema: [{
632
+ type: 'object',
633
+ properties: {
634
+ restrictedFunctions: {
635
+ type: 'array',
636
+ uniqueItems: true,
637
+ items: {
638
+ type: 'string'
639
+ }
640
+ }
641
+ }
642
+ }],
643
+ messages: {
644
+ forbiddenThenCatchFinally: "then()/catch()/finally() is forbidden when invoke {{ name }}()."
645
+ }
646
+ },
647
+ create(context) {
648
+ const configuration = context.options[0] || {};
649
+ const restrictedFunctions = configuration.restrictedFunctions || [];
650
+ function isTopLevelScoped() {
651
+ return context.getScope().block.type === 'Program';
652
+ }
653
+ function isThenCatchFinally(node) {
654
+ return node.property && (node.property.name === 'then' || node.property.name === 'catch' || node.property.name === 'finally');
655
+ }
656
+ return {
657
+ 'CallExpression > MemberExpression.callee'(node) {
658
+ if (isTopLevelScoped()) {
659
+ return;
660
+ }
661
+ if (!isThenCatchFinally(node)) {
662
+ return;
663
+ }
664
+ const callExpression = node.object;
665
+ if (callExpression.type === 'CallExpression' && callExpression.callee.type === 'Identifier' && restrictedFunctions.includes(callExpression.callee.name)) {
666
+ context.report({
667
+ node: node.property,
668
+ messageId: 'forbiddenThenCatchFinally',
669
+ data: {
670
+ name: callExpression.callee.name
671
+ }
672
+ });
673
+ }
674
+ }
675
+ };
676
+ }
677
+ };
678
+
679
+ var noUnnecessaryTemplateLiterals = {
680
+ meta: {
681
+ type: 'problem',
682
+ docs: {
683
+ description: 'Check if a template string contains only one ${}',
684
+ recommended: true
685
+ },
686
+ fixable: 'code',
687
+ schema: [],
688
+ messages: {
689
+ unnecessaryTemplateString: 'Unnecessary template string with only one ${}.'
690
+ }
691
+ },
692
+ create(context) {
693
+ return {
694
+ TemplateLiteral(node) {
695
+ const code = context.sourceCode.getText(node);
696
+ if (code.startsWith('`${') && code.endsWith('}`') && code.split('${').length === 2) {
697
+ context.report({
698
+ node,
699
+ messageId: 'unnecessaryTemplateString',
700
+ fix(fixer) {
701
+ return fixer.replaceText(node, code.substring(3, code.length - 2));
702
+ }
703
+ });
704
+ }
705
+ }
706
+ };
707
+ }
708
+ };
709
+
710
+ var reactBetterExhaustiveDeps = {
533
711
  meta: {
534
712
  type: 'suggestion',
535
713
  docs: {
536
- description:
537
- 'verifies the list of dependencies for Hooks like useEffect and similar',
714
+ description: 'verifies the list of dependencies for Hooks like useEffect and similar',
538
715
  url: 'https://github.com/facebook/react/issues/14920'
539
716
  },
540
717
  fixable: 'code',
541
718
  hasSuggestions: true,
542
- schema: [
543
- {
544
- type: 'object',
545
- additionalProperties: false,
546
- enableDangerousAutofixThisMayCauseInfiniteLoops: false,
547
- properties: {
548
- additionalHooks: {
549
- type: 'string'
550
- },
551
- enableDangerousAutofixThisMayCauseInfiniteLoops: {
552
- type: 'boolean'
553
- },
554
- staticHooks: {
555
- type: 'object',
556
- additionalProperties: {
557
- oneOf: [
558
- {
559
- type: 'boolean'
560
- },
561
- {
562
- type: 'array',
563
- items: {
564
- type: 'boolean'
565
- }
566
- },
567
- {
568
- type: 'object',
569
- additionalProperties: {
570
- type: 'boolean'
571
- }
572
- }
573
- ]
574
- }
575
- },
576
- checkMemoizedVariableIsStatic: {
577
- type: 'boolean'
719
+ schema: [{
720
+ type: 'object',
721
+ additionalProperties: false,
722
+ enableDangerousAutofixThisMayCauseInfiniteLoops: false,
723
+ properties: {
724
+ additionalHooks: {
725
+ type: 'string'
726
+ },
727
+ enableDangerousAutofixThisMayCauseInfiniteLoops: {
728
+ type: 'boolean'
729
+ },
730
+ staticHooks: {
731
+ type: 'object',
732
+ additionalProperties: {
733
+ oneOf: [{
734
+ type: 'boolean'
735
+ }, {
736
+ type: 'array',
737
+ items: {
738
+ type: 'boolean'
739
+ }
740
+ }, {
741
+ type: 'object',
742
+ additionalProperties: {
743
+ type: 'boolean'
744
+ }
745
+ }]
578
746
  }
747
+ },
748
+ checkMemoizedVariableIsStatic: {
749
+ type: 'boolean'
579
750
  }
580
751
  }
581
- ]
752
+ }]
582
753
  },
583
754
  create(context) {
584
- const additionalHooks =
585
- context.options &&
586
- context.options[0] &&
587
- context.options[0].additionalHooks
588
- ? new RegExp(context.options[0].additionalHooks)
589
- : undefined;
590
- const enableDangerousAutofixThisMayCauseInfiniteLoops =
591
- (context.options &&
592
- context.options[0] &&
593
- context.options[0].enableDangerousAutofixThisMayCauseInfiniteLoops) ||
594
- false;
595
- const staticHooks =
596
- (context.options &&
597
- context.options[0] &&
598
- context.options[0].staticHooks) ||
599
- {};
600
- const checkMemoizedVariableIsStatic =
601
- (context.options &&
602
- context.options[0] &&
603
- context.options[0].checkMemoizedVariableIsStatic) ||
604
- false;
755
+ const additionalHooks = context.options && context.options[0] && context.options[0].additionalHooks ? new RegExp(context.options[0].additionalHooks) : undefined;
756
+ const enableDangerousAutofixThisMayCauseInfiniteLoops = context.options && context.options[0] && context.options[0].enableDangerousAutofixThisMayCauseInfiniteLoops || false;
757
+ const staticHooks = context.options && context.options[0] && context.options[0].staticHooks || {};
758
+ const checkMemoizedVariableIsStatic = context.options && context.options[0] && context.options[0].checkMemoizedVariableIsStatic || false;
605
759
  const options = {
606
760
  additionalHooks,
607
761
  enableDangerousAutofixThisMayCauseInfiniteLoops,
@@ -609,11 +763,8 @@ var betterExhaustiveDeps = {
609
763
  checkMemoizedVariableIsStatic
610
764
  };
611
765
  function reportProblem(problem) {
612
- if (
613
- enableDangerousAutofixThisMayCauseInfiniteLoops &&
614
- Array.isArray(problem.suggest) &&
615
- problem.suggest.length > 0
616
- ) {
766
+ if (enableDangerousAutofixThisMayCauseInfiniteLoops &&
767
+ Array.isArray(problem.suggest) && problem.suggest.length > 0) {
617
768
  problem.fix = problem.suggest[0].fix;
618
769
  }
619
770
  context.report(problem);
@@ -633,28 +784,11 @@ var betterExhaustiveDeps = {
633
784
  return result;
634
785
  };
635
786
  }
636
- function visitFunctionWithDependencies(
637
- node,
638
- declaredDependenciesNode,
639
- reactiveHook,
640
- reactiveHookName,
641
- isEffect
642
- ) {
787
+ function visitFunctionWithDependencies(node, declaredDependenciesNode, reactiveHook, reactiveHookName, isEffect) {
643
788
  if (isEffect && node.async) {
644
789
  reportProblem({
645
790
  node: node,
646
- message:
647
- `Effect callbacks are synchronous to prevent race conditions. ` +
648
- `Put the async function inside:\n\n` +
649
- 'useEffect(() => {\n' +
650
- ' async function fetchData() {\n' +
651
- ' // You can await here\n' +
652
- ' const response = await MyAPI.getData(someId);\n' +
653
- ' // ...\n' +
654
- ' }\n' +
655
- ' fetchData();\n' +
656
- `}, [someId]); // Or [] if effect doesn't need props or state\n\n` +
657
- 'Learn more about data fetching with Hooks: https://reactjs.org/link/hooks-data-fetching'
791
+ message: "Effect callbacks are synchronous to prevent race conditions. " + "Put the async function inside:\n\n" + 'useEffect(() => {\n' + ' async function fetchData() {\n' + ' // You can await here\n' + ' const response = await MyAPI.getData(someId);\n' + ' // ...\n' + ' }\n' + ' fetchData();\n' + "}, [someId]); // Or [] if effect doesn't need props or state\n\n" + 'Learn more about data fetching with Hooks: https://reactjs.org/link/hooks-data-fetching'
658
792
  });
659
793
  }
660
794
  const scope = scopeManager.acquire(node);
@@ -675,14 +809,8 @@ var betterExhaustiveDeps = {
675
809
  componentScope = currentScope;
676
810
  }
677
811
  const isArray = Array.isArray;
678
- const memoizedIsStableKnownHookValue = memoizeWithWeakMap(
679
- isStableKnownHookValue,
680
- stableKnownValueCache
681
- );
682
- const memoizedIsFunctionWithoutCapturedValues = memoizeWithWeakMap(
683
- isFunctionWithoutCapturedValues,
684
- functionWithoutCapturedValueCache
685
- );
812
+ const memoizedIsStableKnownHookValue = memoizeWithWeakMap(isStableKnownHookValue, stableKnownValueCache);
813
+ const memoizedIsFunctionWithoutCapturedValues = memoizeWithWeakMap(isFunctionWithoutCapturedValues, functionWithoutCapturedValueCache);
686
814
  function isStableKnownHookValue(resolved) {
687
815
  if (!isArray(resolved.defs)) {
688
816
  return false;
@@ -709,40 +837,27 @@ var betterExhaustiveDeps = {
709
837
  return false;
710
838
  }
711
839
  }
712
- if (
713
- declaration.kind === 'const' &&
714
- init.type === 'Literal' &&
715
- (typeof init.value === 'string' ||
716
- typeof init.value === 'number' ||
717
- init.value == null)
718
- ) {
840
+ if (declaration.kind === 'const' && init.type === 'Literal' && (typeof init.value === 'string' || typeof init.value === 'number' || init.value == null)) {
719
841
  return true;
720
842
  }
721
843
  if (init.type !== 'CallExpression') {
722
844
  return false;
723
845
  }
724
846
  let callee = init.callee;
725
- if (
726
- callee.type === 'MemberExpression' &&
727
- callee.object.name === 'React' &&
728
- callee.property != null &&
729
- !callee.computed
730
- ) {
847
+ if (callee.type === 'MemberExpression' && callee.object.name === 'React' && callee.property != null && !callee.computed) {
731
848
  callee = callee.property;
732
849
  }
733
850
  if (callee.type !== 'Identifier') {
734
851
  return false;
735
852
  }
736
853
  const id = def.node.id;
737
- const { name } = callee;
854
+ const {
855
+ name
856
+ } = callee;
738
857
  if (name === 'useRef' && id.type === 'Identifier') {
739
858
  return true;
740
859
  } else if (name === 'useState' || name === 'useReducer') {
741
- if (
742
- id.type === 'ArrayPattern' &&
743
- id.elements.length === 2 &&
744
- isArray(resolved.identifiers)
745
- ) {
860
+ if (id.type === 'ArrayPattern' && id.elements.length === 2 && isArray(resolved.identifiers)) {
746
861
  if (id.elements[1] === resolved.identifiers[0]) {
747
862
  if (name === 'useState') {
748
863
  const references = resolved.references;
@@ -769,18 +884,11 @@ var betterExhaustiveDeps = {
769
884
  }
770
885
  }
771
886
  } else if (name === 'useTransition') {
772
- if (
773
- id.type === 'ArrayPattern' &&
774
- id.elements.length === 2 &&
775
- Array.isArray(resolved.identifiers) &&
776
- id.elements[1] === resolved.identifiers[0]
777
- ) {
887
+ if (id.type === 'ArrayPattern' && id.elements.length === 2 && Array.isArray(resolved.identifiers) &&
888
+ id.elements[1] === resolved.identifiers[0]) {
778
889
  return true;
779
890
  }
780
- } else if (
781
- options.checkMemoizedVariableIsStatic &&
782
- (name === 'useMemo' || name === 'useCallback')
783
- ) {
891
+ } else if (options.checkMemoizedVariableIsStatic && (name === 'useMemo' || name === 'useCallback')) {
784
892
  const hookArgs = callee.parent.arguments;
785
893
  if (hookArgs.length < 2) {
786
894
  return false;
@@ -790,13 +898,8 @@ var betterExhaustiveDeps = {
790
898
  return true;
791
899
  }
792
900
  for (const dependencyNode of dependencies) {
793
- const dependencyRefernece = resolved.scope.references.find(
794
- reference => reference.identifier === dependencyNode
795
- );
796
- if (
797
- dependencyRefernece !== undefined &&
798
- memoizedIsStableKnownHookValue(dependencyRefernece.resolved)
799
- ) {
901
+ const dependencyRefernece = resolved.scope.references.find(reference => reference.identifier === dependencyNode);
902
+ if (dependencyRefernece !== undefined && memoizedIsStableKnownHookValue(dependencyRefernece.resolved)) {
800
903
  continue;
801
904
  } else {
802
905
  return false;
@@ -805,11 +908,7 @@ var betterExhaustiveDeps = {
805
908
  return true;
806
909
  } else {
807
910
  Object.entries(options.staticHooks).forEach(([key, staticParts]) => {
808
- if (
809
- typeof staticParts === 'object' &&
810
- staticParts.regexp &&
811
- new RegExp(key).test(name)
812
- ) {
911
+ if (typeof staticParts === 'object' && staticParts.regexp && new RegExp(key).test(name)) {
813
912
  options.staticHooks[name] = staticParts.value;
814
913
  }
815
914
  });
@@ -818,23 +917,14 @@ var betterExhaustiveDeps = {
818
917
  if (staticParts === true) {
819
918
  return true;
820
919
  } else if (Array.isArray(staticParts)) {
821
- if (
822
- id.type === 'ArrayPattern' &&
823
- id.elements.length <= staticParts.length &&
824
- Array.isArray(resolved.identifiers)
825
- ) {
920
+ if (id.type === 'ArrayPattern' && id.elements.length <= staticParts.length && Array.isArray(resolved.identifiers)) {
826
921
  const idx = id.elements.indexOf(resolved.identifiers[0]);
827
922
  if (idx >= 0) {
828
923
  return staticParts[idx];
829
924
  }
830
925
  }
831
- } else if (
832
- typeof staticParts === 'object' &&
833
- id.type === 'ObjectPattern'
834
- ) {
835
- const property = id.properties.find(
836
- p => p.key === resolved.identifiers[0]
837
- );
926
+ } else if (typeof staticParts === 'object' && id.type === 'ObjectPattern') {
927
+ const property = id.properties.find(p => p.key === resolved.identifiers[0]);
838
928
  if (property) {
839
929
  return staticParts[property.key.name];
840
930
  }
@@ -862,11 +952,8 @@ var betterExhaustiveDeps = {
862
952
  const childScope = childScopes[i];
863
953
  const childScopeBlock = childScope.block;
864
954
  if (
865
- (fnNode.type === 'FunctionDeclaration' &&
866
- childScopeBlock === fnNode) ||
867
- (fnNode.type === 'VariableDeclarator' &&
868
- childScopeBlock.parent === fnNode)
869
- ) {
955
+ fnNode.type === 'FunctionDeclaration' && childScopeBlock === fnNode ||
956
+ fnNode.type === 'VariableDeclarator' && childScopeBlock.parent === fnNode) {
870
957
  fnScope = childScope;
871
958
  break;
872
959
  }
@@ -879,10 +966,8 @@ var betterExhaustiveDeps = {
879
966
  if (ref.resolved == null) {
880
967
  continue;
881
968
  }
882
- if (
883
- pureScopes.has(ref.resolved.scope) &&
884
- !memoizedIsStableKnownHookValue(ref.resolved)
885
- ) {
969
+ if (pureScopes.has(ref.resolved.scope) &&
970
+ !memoizedIsStableKnownHookValue(ref.resolved)) {
886
971
  return false;
887
972
  }
888
973
  }
@@ -894,9 +979,7 @@ var betterExhaustiveDeps = {
894
979
  let isInReturnedFunction = false;
895
980
  while (curScope.block !== node) {
896
981
  if (curScope.type === 'function') {
897
- isInReturnedFunction =
898
- curScope.block.parent != null &&
899
- curScope.block.parent.type === 'ReturnStatement';
982
+ isInReturnedFunction = curScope.block.parent != null && curScope.block.parent.type === 'ReturnStatement';
900
983
  }
901
984
  curScope = curScope.upper;
902
985
  }
@@ -913,34 +996,19 @@ var betterExhaustiveDeps = {
913
996
  if (!pureScopes.has(reference.resolved.scope)) {
914
997
  continue;
915
998
  }
916
- const referenceNode = fastFindReferenceWithParent(
917
- node,
918
- reference.identifier
919
- );
999
+ const referenceNode = fastFindReferenceWithParent(node, reference.identifier);
920
1000
  const dependencyNode = getDependency(referenceNode);
921
- const dependency = analyzePropertyChain(
922
- dependencyNode,
923
- optionalChains
924
- );
1001
+ const dependency = analyzePropertyChain(dependencyNode, optionalChains);
925
1002
  if (
926
- isEffect &&
927
- dependencyNode.type === 'Identifier' &&
928
- (dependencyNode.parent.type === 'MemberExpression' ||
929
- dependencyNode.parent.type === 'OptionalMemberExpression') &&
930
- !dependencyNode.parent.computed &&
931
- dependencyNode.parent.property.type === 'Identifier' &&
932
- dependencyNode.parent.property.name === 'current' &&
933
- isInsideEffectCleanup(reference)
934
- ) {
1003
+ isEffect &&
1004
+ dependencyNode.type === 'Identifier' && (dependencyNode.parent.type === 'MemberExpression' || dependencyNode.parent.type === 'OptionalMemberExpression') && !dependencyNode.parent.computed && dependencyNode.parent.property.type === 'Identifier' && dependencyNode.parent.property.name === 'current' &&
1005
+ isInsideEffectCleanup(reference)) {
935
1006
  currentRefsInEffectCleanup.set(dependency, {
936
1007
  reference,
937
1008
  dependencyNode
938
1009
  });
939
1010
  }
940
- if (
941
- dependencyNode.parent.type === 'TSTypeQuery' ||
942
- dependencyNode.parent.type === 'TSTypeReference'
943
- ) {
1011
+ if (dependencyNode.parent.type === 'TSTypeQuery' || dependencyNode.parent.type === 'TSTypeReference') {
944
1012
  continue;
945
1013
  }
946
1014
  const def = reference.resolved.defs[0];
@@ -955,9 +1023,7 @@ var betterExhaustiveDeps = {
955
1023
  }
956
1024
  if (!dependencies.has(dependency)) {
957
1025
  const resolved = reference.resolved;
958
- const isStable =
959
- memoizedIsStableKnownHookValue(resolved) ||
960
- memoizedIsFunctionWithoutCapturedValues(resolved);
1026
+ const isStable = memoizedIsStableKnownHookValue(resolved) || memoizedIsFunctionWithoutCapturedValues(resolved);
961
1027
  dependencies.set(dependency, {
962
1028
  isStable,
963
1029
  references: [reference]
@@ -970,39 +1036,33 @@ var betterExhaustiveDeps = {
970
1036
  gatherDependenciesRecursively(childScope);
971
1037
  }
972
1038
  }
973
- currentRefsInEffectCleanup.forEach(
974
- ({ reference, dependencyNode }, dependency) => {
975
- const references = reference.resolved.references;
976
- let foundCurrentAssignment = false;
977
- for (const { identifier } of references) {
978
- const { parent } = identifier;
979
- if (
980
- parent != null &&
981
- parent.type === 'MemberExpression' &&
982
- !parent.computed &&
983
- parent.property.type === 'Identifier' &&
984
- parent.property.name === 'current' &&
985
- parent.parent.type === 'AssignmentExpression' &&
986
- parent.parent.left === parent
987
- ) {
988
- foundCurrentAssignment = true;
989
- break;
990
- }
991
- }
992
- if (foundCurrentAssignment) {
993
- return;
1039
+ currentRefsInEffectCleanup.forEach(({
1040
+ reference,
1041
+ dependencyNode
1042
+ }, dependency) => {
1043
+ const references = reference.resolved.references;
1044
+ let foundCurrentAssignment = false;
1045
+ for (const {
1046
+ identifier
1047
+ } of references) {
1048
+ const {
1049
+ parent
1050
+ } = identifier;
1051
+ if (parent != null &&
1052
+ parent.type === 'MemberExpression' && !parent.computed && parent.property.type === 'Identifier' && parent.property.name === 'current' &&
1053
+ parent.parent.type === 'AssignmentExpression' && parent.parent.left === parent) {
1054
+ foundCurrentAssignment = true;
1055
+ break;
994
1056
  }
995
- reportProblem({
996
- node: dependencyNode.parent.property,
997
- message:
998
- `The ref value '${dependency}.current' will likely have ` +
999
- `changed by the time this effect cleanup function runs. If ` +
1000
- `this ref points to a node rendered by React, copy ` +
1001
- `'${dependency}.current' to a variable inside the effect, and ` +
1002
- `use that variable in the cleanup function.`
1003
- });
1004
1057
  }
1005
- );
1058
+ if (foundCurrentAssignment) {
1059
+ return;
1060
+ }
1061
+ reportProblem({
1062
+ node: dependencyNode.parent.property,
1063
+ message: "The ref value '".concat(dependency, ".current' will likely have ") + "changed by the time this effect cleanup function runs. If " + "this ref points to a node rendered by React, copy " + "'".concat(dependency, ".current' to a variable inside the effect, and ") + "use that variable in the cleanup function."
1064
+ });
1065
+ });
1006
1066
  const staleAssignments = new Set();
1007
1067
  function reportStaleAssignment(writeExpr, key) {
1008
1068
  if (staleAssignments.has(key)) {
@@ -1011,17 +1071,14 @@ var betterExhaustiveDeps = {
1011
1071
  staleAssignments.add(key);
1012
1072
  reportProblem({
1013
1073
  node: writeExpr,
1014
- message:
1015
- `Assignments to the '${key}' variable from inside React Hook ` +
1016
- `${context.getSource(reactiveHook)} will be lost after each ` +
1017
- `render. To preserve the value over time, store it in a useRef ` +
1018
- `Hook and keep the mutable value in the '.current' property. ` +
1019
- `Otherwise, you can move this variable directly inside ` +
1020
- `${context.getSource(reactiveHook)}.`
1074
+ message: "Assignments to the '".concat(key, "' variable from inside React Hook ") + "".concat(context.getSource(reactiveHook), " will be lost after each ") + "render. To preserve the value over time, store it in a useRef " + "Hook and keep the mutable value in the '.current' property. " + "Otherwise, you can move this variable directly inside " + "".concat(context.getSource(reactiveHook), ".")
1021
1075
  });
1022
1076
  }
1023
1077
  const stableDependencies = new Set();
1024
- dependencies.forEach(({ isStable, references }, key) => {
1078
+ dependencies.forEach(({
1079
+ isStable,
1080
+ references
1081
+ }, key) => {
1025
1082
  if (isStable) {
1026
1083
  stableDependencies.add(key);
1027
1084
  }
@@ -1036,7 +1093,9 @@ var betterExhaustiveDeps = {
1036
1093
  }
1037
1094
  if (!declaredDependenciesNode) {
1038
1095
  let setStateInsideEffectWithoutDeps = null;
1039
- dependencies.forEach(({ references }, key) => {
1096
+ dependencies.forEach(({
1097
+ references
1098
+ }, key) => {
1040
1099
  if (setStateInsideEffectWithoutDeps) {
1041
1100
  return;
1042
1101
  }
@@ -1060,7 +1119,9 @@ var betterExhaustiveDeps = {
1060
1119
  });
1061
1120
  });
1062
1121
  if (setStateInsideEffectWithoutDeps) {
1063
- const { suggestedDependencies } = collectRecommendations({
1122
+ const {
1123
+ suggestedDependencies
1124
+ } = collectRecommendations({
1064
1125
  dependencies,
1065
1126
  declaredDependencies: [],
1066
1127
  stableDependencies,
@@ -1069,25 +1130,13 @@ var betterExhaustiveDeps = {
1069
1130
  });
1070
1131
  reportProblem({
1071
1132
  node: reactiveHook,
1072
- message:
1073
- `React Hook ${reactiveHookName} contains a call to '${setStateInsideEffectWithoutDeps}'. ` +
1074
- `Without a list of dependencies, this can lead to an infinite chain of updates. ` +
1075
- `To fix this, pass [` +
1076
- suggestedDependencies.join(', ') +
1077
- `] as a second argument to the ${reactiveHookName} Hook.`,
1078
- suggest: [
1079
- {
1080
- desc: `Add dependencies array: [${suggestedDependencies.join(
1081
- ', '
1082
- )}]`,
1083
- fix(fixer) {
1084
- return fixer.insertTextAfter(
1085
- node,
1086
- `, [${suggestedDependencies.join(', ')}]`
1087
- );
1088
- }
1133
+ message: "React Hook ".concat(reactiveHookName, " contains a call to '").concat(setStateInsideEffectWithoutDeps, "'. ") + "Without a list of dependencies, this can lead to an infinite chain of updates. " + "To fix this, pass [" + suggestedDependencies.join(', ') + "] as a second argument to the ".concat(reactiveHookName, " Hook."),
1134
+ suggest: [{
1135
+ desc: "Add dependencies array: [".concat(suggestedDependencies.join(', '), "]"),
1136
+ fix(fixer) {
1137
+ return fixer.insertTextAfter(node, ", [".concat(suggestedDependencies.join(', '), "]"));
1089
1138
  }
1090
- ]
1139
+ }]
1091
1140
  });
1092
1141
  }
1093
1142
  return;
@@ -1097,11 +1146,7 @@ var betterExhaustiveDeps = {
1097
1146
  if (declaredDependenciesNode.type !== 'ArrayExpression') {
1098
1147
  reportProblem({
1099
1148
  node: declaredDependenciesNode,
1100
- message:
1101
- `React Hook ${context.getSource(reactiveHook)} was passed a ` +
1102
- 'dependency list that is not an array literal. This means we ' +
1103
- "can't statically verify whether you've passed the correct " +
1104
- 'dependencies.'
1149
+ message: "React Hook ".concat(context.getSource(reactiveHook), " was passed a ") + 'dependency list that is not an array literal. This means we ' + "can't statically verify whether you've passed the correct " + 'dependencies.'
1105
1150
  });
1106
1151
  } else {
1107
1152
  declaredDependenciesNode.elements.forEach(declaredDependencyNode => {
@@ -1111,46 +1156,31 @@ var betterExhaustiveDeps = {
1111
1156
  if (declaredDependencyNode.type === 'SpreadElement') {
1112
1157
  reportProblem({
1113
1158
  node: declaredDependencyNode,
1114
- message:
1115
- `React Hook ${context.getSource(reactiveHook)} has a spread ` +
1116
- "element in its dependency array. This means we can't " +
1117
- "statically verify whether you've passed the " +
1118
- 'correct dependencies.'
1159
+ message: "React Hook ".concat(context.getSource(reactiveHook), " has a spread ") + "element in its dependency array. This means we can't " + "statically verify whether you've passed the " + 'correct dependencies.'
1119
1160
  });
1120
1161
  return;
1121
1162
  }
1122
1163
  let declaredDependency;
1123
1164
  try {
1124
- declaredDependency = analyzePropertyChain(
1125
- declaredDependencyNode,
1126
- null
1127
- );
1165
+ declaredDependency = analyzePropertyChain(declaredDependencyNode, null);
1128
1166
  } catch (err) {
1129
1167
  if (/Unsupported node type/.test(err.message)) {
1130
1168
  if (declaredDependencyNode.type === 'Literal') {
1131
1169
  if (dependencies.has(declaredDependencyNode.value)) {
1132
1170
  reportProblem({
1133
1171
  node: declaredDependencyNode,
1134
- message:
1135
- `The ${declaredDependencyNode.raw} literal is not a valid dependency ` +
1136
- `because it never changes. ` +
1137
- `Did you mean to include ${declaredDependencyNode.value} in the array instead?`
1172
+ message: "The ".concat(declaredDependencyNode.raw, " literal is not a valid dependency ") + "because it never changes. " + "Did you mean to include ".concat(declaredDependencyNode.value, " in the array instead?")
1138
1173
  });
1139
1174
  } else {
1140
1175
  reportProblem({
1141
1176
  node: declaredDependencyNode,
1142
- message:
1143
- `The ${declaredDependencyNode.raw} literal is not a valid dependency ` +
1144
- 'because it never changes. You can safely remove it.'
1177
+ message: "The ".concat(declaredDependencyNode.raw, " literal is not a valid dependency ") + 'because it never changes. You can safely remove it.'
1145
1178
  });
1146
1179
  }
1147
1180
  } else {
1148
1181
  reportProblem({
1149
1182
  node: declaredDependencyNode,
1150
- message:
1151
- `React Hook ${context.getSource(reactiveHook)} has a ` +
1152
- `complex expression in the dependency array. ` +
1153
- 'Extract it to a separate variable so it can be statically checked.'
1183
+ message: "React Hook ".concat(context.getSource(reactiveHook), " has a ") + "complex expression in the dependency array. " + 'Extract it to a separate variable so it can be statically checked.'
1154
1184
  });
1155
1185
  }
1156
1186
  return;
@@ -1158,16 +1188,10 @@ var betterExhaustiveDeps = {
1158
1188
  throw err;
1159
1189
  }
1160
1190
  let maybeID = declaredDependencyNode;
1161
- while (
1162
- maybeID.type === 'MemberExpression' ||
1163
- maybeID.type === 'OptionalMemberExpression' ||
1164
- maybeID.type === 'ChainExpression'
1165
- ) {
1191
+ while (maybeID.type === 'MemberExpression' || maybeID.type === 'OptionalMemberExpression' || maybeID.type === 'ChainExpression') {
1166
1192
  maybeID = maybeID.object || maybeID.expression.object;
1167
1193
  }
1168
- const isDeclaredInComponent = !componentScope.through.some(
1169
- ref => ref.identifier === maybeID
1170
- );
1194
+ const isDeclaredInComponent = !componentScope.through.some(ref => ref.identifier === maybeID);
1171
1195
  declaredDependencies.push({
1172
1196
  key: declaredDependency,
1173
1197
  node: declaredDependencyNode
@@ -1190,10 +1214,7 @@ var betterExhaustiveDeps = {
1190
1214
  isEffect
1191
1215
  });
1192
1216
  let suggestedDeps = suggestedDependencies;
1193
- const problemCount =
1194
- duplicateDependencies.size +
1195
- missingDependencies.size +
1196
- unnecessaryDependencies.size;
1217
+ const problemCount = duplicateDependencies.size + missingDependencies.size + unnecessaryDependencies.size;
1197
1218
  if (problemCount === 0) {
1198
1219
  const constructions = scanForConstructions({
1199
1220
  declaredDependencies,
@@ -1201,53 +1222,36 @@ var betterExhaustiveDeps = {
1201
1222
  componentScope,
1202
1223
  scope
1203
1224
  });
1204
- constructions.forEach(
1205
- ({ construction, isUsedOutsideOfHook, depType }) => {
1206
- const wrapperHook =
1207
- depType === 'function' ? 'useCallback' : 'useMemo';
1208
- const constructionType =
1209
- depType === 'function' ? 'definition' : 'initialization';
1210
- const defaultAdvice = `wrap the ${constructionType} of '${construction.name.name}' in its own ${wrapperHook}() Hook.`;
1211
- const advice = isUsedOutsideOfHook
1212
- ? `To fix this, ${defaultAdvice}`
1213
- : `Move it inside the ${reactiveHookName} callback. Alternatively, ${defaultAdvice}`;
1214
- const causation =
1215
- depType === 'conditional' || depType === 'logical expression'
1216
- ? 'could make'
1217
- : 'makes';
1218
- const message =
1219
- `The '${construction.name.name}' ${depType} ${causation} the dependencies of ` +
1220
- `${reactiveHookName} Hook (at line ${declaredDependenciesNode.loc.start.line}) ` +
1221
- `change on every render. ${advice}`;
1222
- let suggest;
1223
- if (
1224
- isUsedOutsideOfHook &&
1225
- construction.type === 'Variable' &&
1226
- depType === 'function'
1227
- ) {
1228
- suggest = [
1229
- {
1230
- desc: `Wrap the ${constructionType} of '${construction.name.name}' in its own ${wrapperHook}() Hook.`,
1231
- fix(fixer) {
1232
- const [before, after] =
1233
- wrapperHook === 'useMemo'
1234
- ? [`useMemo(() => { return `, '; })']
1235
- : ['useCallback(', ')'];
1236
- return [
1237
- fixer.insertTextBefore(construction.node.init, before),
1238
- fixer.insertTextAfter(construction.node.init, after)
1239
- ];
1240
- }
1241
- }
1242
- ];
1243
- }
1244
- reportProblem({
1245
- node: construction.node,
1246
- message,
1247
- suggest
1248
- });
1225
+ constructions.forEach(({
1226
+ construction,
1227
+ isUsedOutsideOfHook,
1228
+ depType
1229
+ }) => {
1230
+ const wrapperHook = depType === 'function' ? 'useCallback' : 'useMemo';
1231
+ const constructionType = depType === 'function' ? 'definition' : 'initialization';
1232
+ const defaultAdvice = "wrap the ".concat(constructionType, " of '").concat(construction.name.name, "' in its own ").concat(wrapperHook, "() Hook.");
1233
+ const advice = isUsedOutsideOfHook ? "To fix this, ".concat(defaultAdvice) : "Move it inside the ".concat(reactiveHookName, " callback. Alternatively, ").concat(defaultAdvice);
1234
+ const causation = depType === 'conditional' || depType === 'logical expression' ? 'could make' : 'makes';
1235
+ const message = "The '".concat(construction.name.name, "' ").concat(depType, " ").concat(causation, " the dependencies of ") + "".concat(reactiveHookName, " Hook (at line ").concat(declaredDependenciesNode.loc.start.line, ") ") + "change on every render. ".concat(advice);
1236
+ let suggest;
1237
+ if (isUsedOutsideOfHook && construction.type === 'Variable' &&
1238
+ depType === 'function') {
1239
+ suggest = [{
1240
+ desc: "Wrap the ".concat(constructionType, " of '").concat(construction.name.name, "' in its own ").concat(wrapperHook, "() Hook."),
1241
+ fix(fixer) {
1242
+ const [before, after] = wrapperHook === 'useMemo' ? ["useMemo(() => { return ", '; })'] : ['useCallback(', ')'];
1243
+ return [
1244
+ fixer.insertTextBefore(construction.node.init, before),
1245
+ fixer.insertTextAfter(construction.node.init, after)];
1246
+ }
1247
+ }];
1249
1248
  }
1250
- );
1249
+ reportProblem({
1250
+ node: construction.node,
1251
+ message,
1252
+ suggest
1253
+ });
1254
+ });
1251
1255
  return;
1252
1256
  }
1253
1257
  if (!isEffect && missingDependencies.size > 0) {
@@ -1287,19 +1291,7 @@ var betterExhaustiveDeps = {
1287
1291
  if (deps.size === 0) {
1288
1292
  return null;
1289
1293
  }
1290
- return (
1291
- (deps.size > 1 ? '' : singlePrefix + ' ') +
1292
- label +
1293
- ' ' +
1294
- (deps.size > 1 ? 'dependencies' : 'dependency') +
1295
- ': ' +
1296
- joinEnglish(
1297
- [...deps].sort().map(name => "'" + formatDependency(name) + "'")
1298
- ) +
1299
- `. Either ${fixVerb} ${
1300
- deps.size > 1 ? 'them' : 'it'
1301
- } or remove the dependency array.`
1302
- );
1294
+ return (deps.size > 1 ? '' : singlePrefix + ' ') + label + ' ' + (deps.size > 1 ? 'dependencies' : 'dependency') + ': ' + joinEnglish([...deps].sort().map(name => "'" + formatDependency(name) + "'")) + ". Either ".concat(fixVerb, " ").concat(deps.size > 1 ? 'them' : 'it', " or remove the dependency array.");
1303
1295
  }
1304
1296
  let extraWarning = '';
1305
1297
  if (unnecessaryDependencies.size > 0) {
@@ -1313,15 +1305,11 @@ var betterExhaustiveDeps = {
1313
1305
  }
1314
1306
  });
1315
1307
  if (badRef != null) {
1316
- extraWarning =
1317
- ` Mutable values like '${badRef}' aren't valid dependencies ` +
1318
- "because mutating them doesn't re-render the component.";
1308
+ extraWarning = " Mutable values like '".concat(badRef, "' aren't valid dependencies ") + "because mutating them doesn't re-render the component.";
1319
1309
  } else if (externalDependencies.size > 0) {
1320
1310
  const dep = [...externalDependencies][0];
1321
1311
  if (!scope.set.has(dep)) {
1322
- extraWarning =
1323
- ` Outer scope values like '${dep}' aren't valid dependencies ` +
1324
- `because mutating them doesn't re-render the component.`;
1312
+ extraWarning = " Outer scope values like '".concat(dep, "' aren't valid dependencies ") + "because mutating them doesn't re-render the component.";
1325
1313
  }
1326
1314
  }
1327
1315
  }
@@ -1336,10 +1324,7 @@ var betterExhaustiveDeps = {
1336
1324
  }
1337
1325
  let isPropsOnlyUsedInMembers = true;
1338
1326
  for (const ref of refs) {
1339
- const id = fastFindReferenceWithParent(
1340
- componentScope.block,
1341
- ref.identifier
1342
- );
1327
+ const id = fastFindReferenceWithParent(componentScope.block, ref.identifier);
1343
1328
  if (!id) {
1344
1329
  isPropsOnlyUsedInMembers = false;
1345
1330
  break;
@@ -1349,20 +1334,13 @@ var betterExhaustiveDeps = {
1349
1334
  isPropsOnlyUsedInMembers = false;
1350
1335
  break;
1351
1336
  }
1352
- if (
1353
- parent.type !== 'MemberExpression' &&
1354
- parent.type !== 'OptionalMemberExpression'
1355
- ) {
1337
+ if (parent.type !== 'MemberExpression' && parent.type !== 'OptionalMemberExpression') {
1356
1338
  isPropsOnlyUsedInMembers = false;
1357
1339
  break;
1358
1340
  }
1359
1341
  }
1360
1342
  if (isPropsOnlyUsedInMembers) {
1361
- extraWarning =
1362
- ` However, 'props' will change when *any* prop changes, so the ` +
1363
- `preferred fix is to destructure the 'props' object outside of ` +
1364
- `the ${reactiveHookName} call and refer to those specific props ` +
1365
- `inside ${context.getSource(reactiveHook)}.`;
1343
+ extraWarning = " However, 'props' will change when *any* prop changes, so the " + "preferred fix is to destructure the 'props' object outside of " + "the ".concat(reactiveHookName, " call and refer to those specific props ") + "inside ".concat(context.getSource(reactiveHook), ".");
1366
1344
  }
1367
1345
  }
1368
1346
  if (!extraWarning && missingDependencies.size > 0) {
@@ -1384,13 +1362,7 @@ var betterExhaustiveDeps = {
1384
1362
  let id;
1385
1363
  for (let i = 0; i < usedDep.references.length; i++) {
1386
1364
  id = usedDep.references[i].identifier;
1387
- if (
1388
- id != null &&
1389
- id.parent != null &&
1390
- (id.parent.type === 'CallExpression' ||
1391
- id.parent.type === 'OptionalCallExpression') &&
1392
- id.parent.callee === id
1393
- ) {
1365
+ if (id != null && id.parent != null && (id.parent.type === 'CallExpression' || id.parent.type === 'OptionalCallExpression') && id.parent.callee === id) {
1394
1366
  isFunctionCall = true;
1395
1367
  break;
1396
1368
  }
@@ -1401,10 +1373,7 @@ var betterExhaustiveDeps = {
1401
1373
  missingCallbackDep = missingDep;
1402
1374
  });
1403
1375
  if (missingCallbackDep != null) {
1404
- extraWarning =
1405
- ` If '${missingCallbackDep}' changes too often, ` +
1406
- `find the parent component that defines it ` +
1407
- `and wrap that definition in useCallback.`;
1376
+ extraWarning = " If '".concat(missingCallbackDep, "' changes too often, ") + "find the parent component that defines it " + "and wrap that definition in useCallback.";
1408
1377
  }
1409
1378
  }
1410
1379
  if (!extraWarning && missingDependencies.size > 0) {
@@ -1422,9 +1391,7 @@ var betterExhaustiveDeps = {
1422
1391
  maybeCall = id.parent;
1423
1392
  while (maybeCall != null && maybeCall !== componentScope.block) {
1424
1393
  if (maybeCall.type === 'CallExpression') {
1425
- const correspondingStateVariable = setStateCallSites.get(
1426
- maybeCall.callee
1427
- );
1394
+ const correspondingStateVariable = setStateCallSites.get(maybeCall.callee);
1428
1395
  if (correspondingStateVariable != null) {
1429
1396
  if (correspondingStateVariable.name === missingDep) {
1430
1397
  setStateRecommendation = {
@@ -1464,27 +1431,13 @@ var betterExhaustiveDeps = {
1464
1431
  if (setStateRecommendation != null) {
1465
1432
  switch (setStateRecommendation.form) {
1466
1433
  case 'reducer':
1467
- extraWarning =
1468
- ` You can also replace multiple useState variables with useReducer ` +
1469
- `if '${setStateRecommendation.setter}' needs the ` +
1470
- `current value of '${setStateRecommendation.missingDep}'.`;
1434
+ extraWarning = " You can also replace multiple useState variables with useReducer " + "if '".concat(setStateRecommendation.setter, "' needs the ") + "current value of '".concat(setStateRecommendation.missingDep, "'.");
1471
1435
  break;
1472
1436
  case 'inlineReducer':
1473
- extraWarning =
1474
- ` If '${setStateRecommendation.setter}' needs the ` +
1475
- `current value of '${setStateRecommendation.missingDep}', ` +
1476
- `you can also switch to useReducer instead of useState and ` +
1477
- `read '${setStateRecommendation.missingDep}' in the reducer.`;
1437
+ extraWarning = " If '".concat(setStateRecommendation.setter, "' needs the ") + "current value of '".concat(setStateRecommendation.missingDep, "', ") + "you can also switch to useReducer instead of useState and " + "read '".concat(setStateRecommendation.missingDep, "' in the reducer.");
1478
1438
  break;
1479
1439
  case 'updater':
1480
- extraWarning = ` You can also do a functional update '${
1481
- setStateRecommendation.setter
1482
- }(${setStateRecommendation.missingDep.slice(
1483
- 0,
1484
- 1
1485
- )} => ...)' if you only need '${
1486
- setStateRecommendation.missingDep
1487
- }' in the '${setStateRecommendation.setter}' call.`;
1440
+ extraWarning = " You can also do a functional update '".concat(setStateRecommendation.setter, "(").concat(setStateRecommendation.missingDep.slice(0, 1), " => ...)' if you only need '").concat(setStateRecommendation.missingDep, "' in the '").concat(setStateRecommendation.setter, "' call.");
1488
1441
  break;
1489
1442
  default:
1490
1443
  throw new Error('Unknown case.');
@@ -1493,35 +1446,14 @@ var betterExhaustiveDeps = {
1493
1446
  }
1494
1447
  reportProblem({
1495
1448
  node: declaredDependenciesNode,
1496
- message:
1497
- `React Hook ${context.getSource(reactiveHook)} has ` +
1498
- (getWarningMessage(missingDependencies, 'a', 'missing', 'include') ||
1499
- getWarningMessage(
1500
- unnecessaryDependencies,
1501
- 'an',
1502
- 'unnecessary',
1503
- 'exclude'
1504
- ) ||
1505
- getWarningMessage(
1506
- duplicateDependencies,
1507
- 'a',
1508
- 'duplicate',
1509
- 'omit'
1510
- )) +
1511
- extraWarning,
1512
- suggest: [
1513
- {
1514
- desc: `Update the dependencies array to be: [${suggestedDeps
1515
- .map(element => formatDependency(element))
1516
- .join(', ')}]`,
1517
- fix(fixer) {
1518
- return fixer.replaceText(
1519
- declaredDependenciesNode,
1520
- `[${suggestedDeps.map(element => formatDependency(element)).join(', ')}]`
1521
- );
1522
- }
1523
- }
1524
- ]
1449
+ message: "React Hook ".concat(context.getSource(reactiveHook), " has ") + (
1450
+ getWarningMessage(missingDependencies, 'a', 'missing', 'include') || getWarningMessage(unnecessaryDependencies, 'an', 'unnecessary', 'exclude') || getWarningMessage(duplicateDependencies, 'a', 'duplicate', 'omit')) + extraWarning,
1451
+ suggest: [{
1452
+ desc: "Update the dependencies array to be: [".concat(suggestedDeps.map(element => formatDependency(element)).join(', '), "]"),
1453
+ fix(fixer) {
1454
+ return fixer.replaceText(declaredDependenciesNode, "[".concat(suggestedDeps.map(element => formatDependency(element)).join(', '), "]"));
1455
+ }
1456
+ }]
1525
1457
  });
1526
1458
  }
1527
1459
  function visitCallExpression(node) {
@@ -1537,23 +1469,15 @@ var betterExhaustiveDeps = {
1537
1469
  if (!callback) {
1538
1470
  reportProblem({
1539
1471
  node: reactiveHook,
1540
- message:
1541
- `React Hook ${reactiveHookName} requires an effect callback. ` +
1542
- `Did you forget to pass a callback to the hook?`
1472
+ message: "React Hook ".concat(reactiveHookName, " requires an effect callback. ") + "Did you forget to pass a callback to the hook?"
1543
1473
  });
1544
1474
  return;
1545
1475
  }
1546
1476
  if (!declaredDependenciesNode && !isEffect) {
1547
- if (
1548
- reactiveHookName === 'useMemo' ||
1549
- reactiveHookName === 'useCallback'
1550
- ) {
1477
+ if (reactiveHookName === 'useMemo' || reactiveHookName === 'useCallback') {
1551
1478
  reportProblem({
1552
1479
  node: reactiveHook,
1553
- message:
1554
- `React Hook ${reactiveHookName} does nothing when called with ` +
1555
- `only one argument. Did you forget to pass an array of ` +
1556
- `dependencies?`
1480
+ message: "React Hook ".concat(reactiveHookName, " does nothing when called with ") + "only one argument. Did you forget to pass an array of " + "dependencies?"
1557
1481
  });
1558
1482
  }
1559
1483
  return;
@@ -1561,24 +1485,13 @@ var betterExhaustiveDeps = {
1561
1485
  switch (callback.type) {
1562
1486
  case 'FunctionExpression':
1563
1487
  case 'ArrowFunctionExpression':
1564
- visitFunctionWithDependencies(
1565
- callback,
1566
- declaredDependenciesNode,
1567
- reactiveHook,
1568
- reactiveHookName,
1569
- isEffect
1570
- );
1488
+ visitFunctionWithDependencies(callback, declaredDependenciesNode, reactiveHook, reactiveHookName, isEffect);
1571
1489
  return;
1572
1490
  case 'Identifier':
1573
1491
  if (!declaredDependenciesNode) {
1574
1492
  return;
1575
1493
  }
1576
- if (
1577
- declaredDependenciesNode.elements &&
1578
- declaredDependenciesNode.elements.some(
1579
- el => el && el.type === 'Identifier' && el.name === callback.name
1580
- )
1581
- ) {
1494
+ if (declaredDependenciesNode.elements && declaredDependenciesNode.elements.some(el => el && el.type === 'Identifier' && el.name === callback.name)) {
1582
1495
  return;
1583
1496
  }
1584
1497
  const variable = context.getScope().set.get(callback.name);
@@ -1594,13 +1507,7 @@ var betterExhaustiveDeps = {
1594
1507
  }
1595
1508
  switch (def.node.type) {
1596
1509
  case 'FunctionDeclaration':
1597
- visitFunctionWithDependencies(
1598
- def.node,
1599
- declaredDependenciesNode,
1600
- reactiveHook,
1601
- reactiveHookName,
1602
- isEffect
1603
- );
1510
+ visitFunctionWithDependencies(def.node, declaredDependenciesNode, reactiveHook, reactiveHookName, isEffect);
1604
1511
  return;
1605
1512
  case 'VariableDeclarator':
1606
1513
  const init = def.node.init;
@@ -1610,13 +1517,7 @@ var betterExhaustiveDeps = {
1610
1517
  switch (init.type) {
1611
1518
  case 'ArrowFunctionExpression':
1612
1519
  case 'FunctionExpression':
1613
- visitFunctionWithDependencies(
1614
- init,
1615
- declaredDependenciesNode,
1616
- reactiveHook,
1617
- reactiveHookName,
1618
- isEffect
1619
- );
1520
+ visitFunctionWithDependencies(init, declaredDependenciesNode, reactiveHook, reactiveHookName, isEffect);
1620
1521
  return;
1621
1522
  }
1622
1523
  break;
@@ -1625,28 +1526,19 @@ var betterExhaustiveDeps = {
1625
1526
  default:
1626
1527
  reportProblem({
1627
1528
  node: reactiveHook,
1628
- message:
1629
- `React Hook ${reactiveHookName} received a function whose dependencies ` +
1630
- `are unknown. Pass an inline function instead.`
1529
+ message: "React Hook ".concat(reactiveHookName, " received a function whose dependencies ") + "are unknown. Pass an inline function instead."
1631
1530
  });
1632
1531
  return;
1633
1532
  }
1634
1533
  reportProblem({
1635
1534
  node: reactiveHook,
1636
- message:
1637
- `React Hook ${reactiveHookName} has a missing dependency: '${callback.name}'. ` +
1638
- `Either include it or remove the dependency array.`,
1639
- suggest: [
1640
- {
1641
- desc: `Update the dependencies array to be: [${callback.name}]`,
1642
- fix(fixer) {
1643
- return fixer.replaceText(
1644
- declaredDependenciesNode,
1645
- `[${callback.name}]`
1646
- );
1647
- }
1535
+ message: "React Hook ".concat(reactiveHookName, " has a missing dependency: '").concat(callback.name, "'. ") + "Either include it or remove the dependency array.",
1536
+ suggest: [{
1537
+ desc: "Update the dependencies array to be: [".concat(callback.name, "]"),
1538
+ fix(fixer) {
1539
+ return fixer.replaceText(declaredDependenciesNode, "[".concat(callback.name, "]"));
1648
1540
  }
1649
- ]
1541
+ }]
1650
1542
  });
1651
1543
  }
1652
1544
  return {
@@ -1677,7 +1569,9 @@ function collectRecommendations({
1677
1569
  parent.isSubtreeUsed = true;
1678
1570
  });
1679
1571
  });
1680
- declaredDependencies.forEach(({ key }) => {
1572
+ declaredDependencies.forEach(({
1573
+ key
1574
+ }) => {
1681
1575
  const node = getOrCreateNodeByPath(depTree, key);
1682
1576
  node.isSatisfiedRecursively = true;
1683
1577
  });
@@ -1712,12 +1606,7 @@ function collectRecommendations({
1712
1606
  }
1713
1607
  const missingDependencies = new Set();
1714
1608
  const satisfyingDependencies = new Set();
1715
- scanTreeRecursively(
1716
- depTree,
1717
- missingDependencies,
1718
- satisfyingDependencies,
1719
- key => key
1720
- );
1609
+ scanTreeRecursively(depTree, missingDependencies, satisfyingDependencies, key => key);
1721
1610
  function scanTreeRecursively(node, missingPaths, satisfyingPaths, keyToPath) {
1722
1611
  node.children.forEach((child, key) => {
1723
1612
  const path = keyToPath(key);
@@ -1731,29 +1620,22 @@ function collectRecommendations({
1731
1620
  missingPaths.add(path);
1732
1621
  return;
1733
1622
  }
1734
- scanTreeRecursively(
1735
- child,
1736
- missingPaths,
1737
- satisfyingPaths,
1738
- childKey => path + '.' + childKey
1739
- );
1623
+ scanTreeRecursively(child, missingPaths, satisfyingPaths, childKey => path + '.' + childKey);
1740
1624
  });
1741
1625
  }
1742
1626
  const suggestedDependencies = [];
1743
1627
  const unnecessaryDependencies = new Set();
1744
1628
  const duplicateDependencies = new Set();
1745
- declaredDependencies.forEach(({ key }) => {
1629
+ declaredDependencies.forEach(({
1630
+ key
1631
+ }) => {
1746
1632
  if (satisfyingDependencies.has(key)) {
1747
1633
  if (!suggestedDependencies.includes(key)) {
1748
1634
  suggestedDependencies.push(key);
1749
1635
  } else {
1750
1636
  duplicateDependencies.add(key);
1751
1637
  }
1752
- } else if (
1753
- isEffect &&
1754
- !key.endsWith('.current') &&
1755
- !externalDependencies.has(key)
1756
- ) {
1638
+ } else if (isEffect && !key.endsWith('.current') && !externalDependencies.has(key)) {
1757
1639
  if (!suggestedDependencies.includes(key)) {
1758
1640
  suggestedDependencies.push(key);
1759
1641
  }
@@ -1783,18 +1665,12 @@ function getConstructionExpressionType(node) {
1783
1665
  case 'ClassExpression':
1784
1666
  return 'class';
1785
1667
  case 'ConditionalExpression':
1786
- if (
1787
- getConstructionExpressionType(node.consequent) != null ||
1788
- getConstructionExpressionType(node.alternate) != null
1789
- ) {
1668
+ if (getConstructionExpressionType(node.consequent) != null || getConstructionExpressionType(node.alternate) != null) {
1790
1669
  return 'conditional';
1791
1670
  }
1792
1671
  return null;
1793
1672
  case 'LogicalExpression':
1794
- if (
1795
- getConstructionExpressionType(node.left) != null ||
1796
- getConstructionExpressionType(node.right) != null
1797
- ) {
1673
+ if (getConstructionExpressionType(node.left) != null || getConstructionExpressionType(node.right) != null) {
1798
1674
  return 'logical expression';
1799
1675
  }
1800
1676
  return null;
@@ -1827,41 +1703,32 @@ function scanForConstructions({
1827
1703
  componentScope,
1828
1704
  scope
1829
1705
  }) {
1830
- const constructions = declaredDependencies
1831
- .map(({ key }) => {
1832
- const ref = componentScope.variables.find(v => v.name === key);
1833
- if (ref == null) {
1834
- return null;
1835
- }
1836
- const node = ref.defs[0];
1837
- if (node == null) {
1838
- return null;
1839
- }
1840
- if (
1841
- node.type === 'Variable' &&
1842
- node.node.type === 'VariableDeclarator' &&
1843
- node.node.id.type === 'Identifier' &&
1844
- node.node.init != null
1845
- ) {
1846
- const constantExpressionType = getConstructionExpressionType(
1847
- node.node.init
1848
- );
1849
- if (constantExpressionType != null) {
1850
- return [ref, constantExpressionType];
1851
- }
1852
- }
1853
- if (
1854
- node.type === 'FunctionName' &&
1855
- node.node.type === 'FunctionDeclaration'
1856
- ) {
1857
- return [ref, 'function'];
1858
- }
1859
- if (node.type === 'ClassName' && node.node.type === 'ClassDeclaration') {
1860
- return [ref, 'class'];
1861
- }
1706
+ const constructions = declaredDependencies.map(({
1707
+ key
1708
+ }) => {
1709
+ const ref = componentScope.variables.find(v => v.name === key);
1710
+ if (ref == null) {
1862
1711
  return null;
1863
- })
1864
- .filter(Boolean);
1712
+ }
1713
+ const node = ref.defs[0];
1714
+ if (node == null) {
1715
+ return null;
1716
+ }
1717
+ if (node.type === 'Variable' && node.node.type === 'VariableDeclarator' && node.node.id.type === 'Identifier' &&
1718
+ node.node.init != null) {
1719
+ const constantExpressionType = getConstructionExpressionType(node.node.init);
1720
+ if (constantExpressionType != null) {
1721
+ return [ref, constantExpressionType];
1722
+ }
1723
+ }
1724
+ if (node.type === 'FunctionName' && node.node.type === 'FunctionDeclaration') {
1725
+ return [ref, 'function'];
1726
+ }
1727
+ if (node.type === 'ClassName' && node.node.type === 'ClassDeclaration') {
1728
+ return [ref, 'class'];
1729
+ }
1730
+ return null;
1731
+ }).filter(Boolean);
1865
1732
  function isUsedOutsideOfHook(ref) {
1866
1733
  let foundWriteExpr = false;
1867
1734
  for (let i = 0; i < ref.references.length; i++) {
@@ -1877,10 +1744,8 @@ function scanForConstructions({
1877
1744
  while (currentScope !== scope && currentScope != null) {
1878
1745
  currentScope = currentScope.upper;
1879
1746
  }
1880
- if (
1881
- currentScope !== scope &&
1882
- !isAncestorNodeOf(declaredDependenciesNode, reference.identifier)
1883
- ) {
1747
+ if (currentScope !== scope &&
1748
+ !isAncestorNodeOf(declaredDependenciesNode, reference.identifier)) {
1884
1749
  return true;
1885
1750
  }
1886
1751
  }
@@ -1893,26 +1758,10 @@ function scanForConstructions({
1893
1758
  }));
1894
1759
  }
1895
1760
  function getDependency(node) {
1896
- if (
1897
- (node.parent.type === 'MemberExpression' ||
1898
- node.parent.type === 'OptionalMemberExpression') &&
1899
- node.parent.object === node &&
1900
- node.parent.property.name !== 'current' &&
1901
- !node.parent.computed &&
1902
- !(
1903
- node.parent.parent != null &&
1904
- (node.parent.parent.type === 'CallExpression' ||
1905
- node.parent.parent.type === 'OptionalCallExpression') &&
1906
- node.parent.parent.callee === node.parent
1907
- )
1908
- ) {
1761
+ if ((node.parent.type === 'MemberExpression' || node.parent.type === 'OptionalMemberExpression') && node.parent.object === node && node.parent.property.name !== 'current' && !node.parent.computed && !(node.parent.parent != null && (node.parent.parent.type === 'CallExpression' || node.parent.parent.type === 'OptionalCallExpression') && node.parent.parent.callee === node.parent)) {
1909
1762
  return getDependency(node.parent);
1910
1763
  } else if (
1911
- node.type === 'MemberExpression' &&
1912
- node.parent &&
1913
- node.parent.type === 'AssignmentExpression' &&
1914
- node.parent.left === node
1915
- ) {
1764
+ node.type === 'MemberExpression' && node.parent && node.parent.type === 'AssignmentExpression' && node.parent.left === node) {
1916
1765
  return node.object;
1917
1766
  }
1918
1767
  return node;
@@ -1938,36 +1787,30 @@ function analyzePropertyChain(node, optionalChains) {
1938
1787
  } else if (node.type === 'MemberExpression' && !node.computed) {
1939
1788
  const object = analyzePropertyChain(node.object, optionalChains);
1940
1789
  const property = analyzePropertyChain(node.property, null);
1941
- const result = `${object}.${property}`;
1790
+ const result = "".concat(object, ".").concat(property);
1942
1791
  markNode(node, optionalChains, result);
1943
1792
  return result;
1944
1793
  } else if (node.type === 'OptionalMemberExpression' && !node.computed) {
1945
1794
  const object = analyzePropertyChain(node.object, optionalChains);
1946
1795
  const property = analyzePropertyChain(node.property, null);
1947
- const result = `${object}.${property}`;
1796
+ const result = "".concat(object, ".").concat(property);
1948
1797
  markNode(node, optionalChains, result);
1949
1798
  return result;
1950
1799
  } else if (node.type === 'ChainExpression' && !node.computed) {
1951
1800
  const expression = node.expression;
1952
1801
  if (expression.type === 'CallExpression') {
1953
- throw new Error(`Unsupported node type: ${expression.type}`);
1802
+ throw new Error("Unsupported node type: ".concat(expression.type));
1954
1803
  }
1955
1804
  const object = analyzePropertyChain(expression.object, optionalChains);
1956
1805
  const property = analyzePropertyChain(expression.property, null);
1957
- const result = `${object}.${property}`;
1806
+ const result = "".concat(object, ".").concat(property);
1958
1807
  markNode(expression, optionalChains, result);
1959
1808
  return result;
1960
1809
  }
1961
- throw new Error(`Unsupported node type: ${node.type}`);
1810
+ throw new Error("Unsupported node type: ".concat(node.type));
1962
1811
  }
1963
1812
  function getNodeWithoutReactNamespace(node) {
1964
- if (
1965
- node.type === 'MemberExpression' &&
1966
- node.object.type === 'Identifier' &&
1967
- node.object.name === 'React' &&
1968
- node.property.type === 'Identifier' &&
1969
- !node.computed
1970
- ) {
1813
+ if (node.type === 'MemberExpression' && node.object.type === 'Identifier' && node.object.name === 'React' && node.property.type === 'Identifier' && !node.computed) {
1971
1814
  return node.property;
1972
1815
  }
1973
1816
  return node;
@@ -2046,28 +1889,17 @@ function joinEnglish(arr) {
2046
1889
  return s;
2047
1890
  }
2048
1891
  function isNodeLike(val) {
2049
- return (
2050
- typeof val === 'object' &&
2051
- val != null &&
2052
- !Array.isArray(val) &&
2053
- typeof val.type === 'string'
2054
- );
1892
+ return typeof val === 'object' && val != null && !Array.isArray(val) && typeof val.type === 'string';
2055
1893
  }
2056
1894
  function isSameIdentifier(a, b) {
2057
- return (
2058
- (a.type === 'Identifier' || a.type === 'JSXIdentifier') &&
2059
- a.type === b.type &&
2060
- a.name === b.name &&
2061
- a.range[0] === b.range[0] &&
2062
- a.range[1] === b.range[1]
2063
- );
1895
+ return (a.type === 'Identifier' || a.type === 'JSXIdentifier') && a.type === b.type && a.name === b.name && a.range[0] === b.range[0] && a.range[1] === b.range[1];
2064
1896
  }
2065
1897
  function isAncestorNodeOf(a, b) {
2066
1898
  return a.range[0] <= b.range[0] && a.range[1] >= b.range[1];
2067
1899
  }
2068
1900
 
2069
1901
  const Components = require('eslint-plugin-react/lib/util/Components');
2070
- var hookUseRef = {
1902
+ var reactHookUseRef = {
2071
1903
  meta: {
2072
1904
  docs: {
2073
1905
  description: 'Ensure naming of useRef hook value.',
@@ -2075,12 +1907,14 @@ var hookUseRef = {
2075
1907
  },
2076
1908
  schema: [],
2077
1909
  type: 'suggestion',
2078
- hasSuggestions: true
1910
+ hasSuggestions: true,
1911
+ messages: {
1912
+ useRefName: 'useRef call is not end with "Ref"'
1913
+ }
2079
1914
  },
2080
1915
  create: Components.detect((context, component, util) => ({
2081
1916
  CallExpression(node) {
2082
- const isImmediateReturn =
2083
- node.parent && node.parent.type === 'ReturnStatement';
1917
+ const isImmediateReturn = node.parent && node.parent.type === 'ReturnStatement';
2084
1918
  if (isImmediateReturn || !util.isReactHookCall(node, ['useRef'])) {
2085
1919
  return;
2086
1920
  }
@@ -2091,7 +1925,7 @@ var hookUseRef = {
2091
1925
  if (!variable.endsWith('Ref')) {
2092
1926
  context.report({
2093
1927
  node: node,
2094
- message: 'useRef call is not end with "Ref"'
1928
+ messageId: 'useRefName'
2095
1929
  });
2096
1930
  }
2097
1931
  }
@@ -2100,54 +1934,39 @@ var hookUseRef = {
2100
1934
 
2101
1935
  function* updateImportStatement(context, fixer, key) {
2102
1936
  const sourceCode = context.sourceCode;
2103
- const importNode = sourceCode.ast.body.find(
2104
- node => node.type === 'ImportDeclaration' && node.source.value === 'react'
2105
- );
1937
+ const importNode = sourceCode.ast.body.find(node => node.type === 'ImportDeclaration' && node.source.value === 'react');
2106
1938
  if (!importNode) {
2107
- yield fixer.insertTextBefore(
2108
- sourceCode.ast.body[0],
2109
- `import { ${key} } from 'react';\n`
2110
- );
1939
+ yield fixer.insertTextBefore(sourceCode.ast.body[0], "import { ".concat(key, " } from 'react';\n"));
2111
1940
  return;
2112
1941
  }
2113
- if (
2114
- importNode.specifiers.length === 1 &&
2115
- importNode.specifiers[0].type === 'ImportDefaultSpecifier'
2116
- ) {
2117
- yield fixer.insertTextAfter(importNode.specifiers[0], `, { ${key} }`);
1942
+ if (importNode.specifiers.length === 1 && importNode.specifiers[0].type === 'ImportDefaultSpecifier') {
1943
+ yield fixer.insertTextAfter(importNode.specifiers[0], ", { ".concat(key, " }"));
2118
1944
  return;
2119
1945
  }
2120
- const alreadyImportedKeys = importNode.specifiers
2121
- .filter(specifier => specifier.type === 'ImportSpecifier')
2122
- .map(specifier => specifier.imported.name);
1946
+ const alreadyImportedKeys = importNode.specifiers.filter(specifier => specifier.type === 'ImportSpecifier').map(specifier => specifier.imported.name);
2123
1947
  if (alreadyImportedKeys.includes(key)) {
2124
1948
  return;
2125
1949
  }
2126
- yield fixer.insertTextAfter([...importNode.specifiers].pop(), `, ${key}`);
1950
+ yield fixer.insertTextAfter([...importNode.specifiers].pop(), ", ".concat(key));
2127
1951
  }
2128
- var preferNamedPropertyAccess = utils.ESLintUtils.RuleCreator.withoutDocs({
1952
+ var reactPreferNamedPropertyAccess = utils.ESLintUtils.RuleCreator.withoutDocs({
2129
1953
  defaultOptions: [],
2130
1954
  meta: {
2131
1955
  type: 'layout',
2132
1956
  fixable: 'code',
2133
1957
  docs: {
2134
- description:
2135
- 'Enforce importing each member of React namespace separately instead of accessing them through React namespace',
1958
+ description: 'Enforce importing each member of React namespace separately instead of accessing them through React namespace',
2136
1959
  recommended: 'recommended'
2137
1960
  },
2138
1961
  messages: {
2139
- illegalReactPropertyAccess:
2140
- 'Illegal React property access: {{name}}. Use named import instead.'
1962
+ illegalReactPropertyAccess: 'Illegal React property access: {{name}}. Use named import instead.'
2141
1963
  },
2142
1964
  schema: []
2143
1965
  },
2144
1966
  create(context) {
2145
1967
  return {
2146
1968
  TSQualifiedName(node) {
2147
- if (
2148
- ('name' in node.left && node.left.name !== 'React') ||
2149
- ('name' in node.right && node.right.name.endsWith('Event'))
2150
- ) {
1969
+ if ('name' in node.left && node.left.name !== 'React' || 'name' in node.right && node.right.name.endsWith('Event')) {
2151
1970
  return;
2152
1971
  }
2153
1972
  context.report({
@@ -2182,7 +2001,7 @@ var preferNamedPropertyAccess = utils.ESLintUtils.RuleCreator.withoutDocs({
2182
2001
  }
2183
2002
  });
2184
2003
 
2185
- var preferSxProp = {
2004
+ var reactPreferSxProp = {
2186
2005
  meta: {
2187
2006
  docs: {
2188
2007
  description: 'Prefer using sx prop instead of inline styles',
@@ -2190,36 +2009,29 @@ var preferSxProp = {
2190
2009
  recommended: true
2191
2010
  },
2192
2011
  messages: {
2193
- preferSxProp:
2194
- 'Avoid using inline styles, use sx prop or tss-react or styled-component instead'
2012
+ preferSxProp: 'Avoid using inline styles, use sx prop or tss-react or styled-component instead'
2195
2013
  },
2196
- schema: [
2197
- {
2198
- type: 'object',
2199
- properties: {
2200
- allowedFor: {
2201
- type: 'array',
2202
- uniqueItems: true,
2203
- items: { type: 'string' }
2014
+ schema: [{
2015
+ type: 'object',
2016
+ properties: {
2017
+ allowedFor: {
2018
+ type: 'array',
2019
+ uniqueItems: true,
2020
+ items: {
2021
+ type: 'string'
2204
2022
  }
2205
2023
  }
2206
2024
  }
2207
- ]
2025
+ }]
2208
2026
  },
2209
2027
  create(context) {
2210
2028
  const configuration = context.options[0] || {};
2211
2029
  const allowedFor = configuration.allowedFor || [];
2212
2030
  function checkComponent(node) {
2213
2031
  const parentName = node.parent.name;
2214
- const tag =
2215
- parentName.name ||
2216
- `${parentName.object.name}.${parentName.property.name}`;
2032
+ const tag = parentName.name || "".concat(parentName.object.name, ".").concat(parentName.property.name);
2217
2033
  const componentName = parentName.name || parentName.property.name;
2218
- if (
2219
- componentName &&
2220
- typeof componentName[0] === 'string' &&
2221
- componentName[0] !== componentName[0].toUpperCase()
2222
- ) {
2034
+ if (componentName && typeof componentName[0] === 'string' && componentName[0] !== componentName[0].toUpperCase()) {
2223
2035
  return;
2224
2036
  }
2225
2037
  if (allowedFor.includes(tag)) {
@@ -2235,9 +2047,7 @@ var preferSxProp = {
2235
2047
  }
2236
2048
  function checkDOMNodes(node) {
2237
2049
  const tag = node.parent.name.name;
2238
- if (
2239
- !(tag && typeof tag === 'string' && tag[0] !== tag[0].toUpperCase())
2240
- ) {
2050
+ if (!(tag && typeof tag === 'string' && tag[0] !== tag[0].toUpperCase())) {
2241
2051
  return;
2242
2052
  }
2243
2053
  if (allowedFor.includes(tag)) {
@@ -2277,25 +2087,24 @@ function getBasicIdentifier(node) {
2277
2087
  }
2278
2088
  function getBaseIdentifier(node) {
2279
2089
  switch (node.type) {
2280
- case 'Identifier': {
2281
- return node;
2282
- }
2283
- case 'CallExpression': {
2284
- return getBaseIdentifier(node.callee);
2285
- }
2286
- case 'MemberExpression': {
2287
- return getBaseIdentifier(node.object);
2288
- }
2090
+ case 'Identifier':
2091
+ {
2092
+ return node;
2093
+ }
2094
+ case 'CallExpression':
2095
+ {
2096
+ return getBaseIdentifier(node.callee);
2097
+ }
2098
+ case 'MemberExpression':
2099
+ {
2100
+ return getBaseIdentifier(node.object);
2101
+ }
2289
2102
  }
2290
2103
  return null;
2291
2104
  }
2292
2105
  function getStyesObj(node) {
2293
2106
  const isMakeStyles = node.callee.name === 'makeStyles';
2294
- const isModernApi =
2295
- node.callee.type === 'MemberExpression' &&
2296
- node.callee.property.name === 'create' &&
2297
- getBaseIdentifier(node.callee.object) &&
2298
- getBaseIdentifier(node.callee.object).name === 'tss';
2107
+ const isModernApi = node.callee.type === 'MemberExpression' && node.callee.property.name === 'create' && getBaseIdentifier(node.callee.object) && getBaseIdentifier(node.callee.object).name === 'tss';
2299
2108
  if (!isMakeStyles && !isModernApi) {
2300
2109
  return;
2301
2110
  }
@@ -2315,35 +2124,51 @@ function getStyesObj(node) {
2315
2124
  return styles;
2316
2125
  case 'ArrowFunctionExpression':
2317
2126
  {
2318
- const { body } = styles;
2127
+ const {
2128
+ body
2129
+ } = styles;
2319
2130
  switch (body.type) {
2320
2131
  case 'ObjectExpression':
2321
2132
  return body;
2322
- case 'BlockStatement': {
2323
- let stylesObj;
2324
- body.body.forEach(bodyNode => {
2325
- if (
2326
- bodyNode.type === 'ReturnStatement' &&
2327
- bodyNode.argument.type === 'ObjectExpression'
2328
- ) {
2329
- stylesObj = bodyNode.argument;
2330
- }
2331
- });
2332
- return stylesObj;
2333
- }
2133
+ case 'BlockStatement':
2134
+ {
2135
+ let stylesObj;
2136
+ body.body.forEach(bodyNode => {
2137
+ if (bodyNode.type === 'ReturnStatement' && bodyNode.argument.type === 'ObjectExpression') {
2138
+ stylesObj = bodyNode.argument;
2139
+ }
2140
+ });
2141
+ return stylesObj;
2142
+ }
2334
2143
  }
2335
2144
  }
2336
2145
  break;
2337
2146
  }
2338
2147
  }
2148
+ function loopStylesObj(node, callback) {
2149
+ if (node && node.type === 'ObjectExpression') {
2150
+ node.properties.forEach(property => {
2151
+ if (property.type === 'Property' && property.value) {
2152
+ if (property.value.type === 'ObjectExpression') {
2153
+ loopStylesObj(property.value, callback);
2154
+ } else {
2155
+ callback(property.value);
2156
+ }
2157
+ }
2158
+ });
2159
+ }
2160
+ }
2339
2161
 
2340
- var classNaming = {
2162
+ var tssClassNaming = {
2341
2163
  meta: {
2342
2164
  type: 'problem',
2343
2165
  docs: {
2344
2166
  description: 'Enforce camelCase class names in TSS',
2345
2167
  category: 'Best Practices',
2346
2168
  recommended: true
2169
+ },
2170
+ messages: {
2171
+ camelCase: 'Class `{{ className }}` must be camelCase in TSS.'
2347
2172
  }
2348
2173
  },
2349
2174
  create: function rule(context) {
@@ -2357,17 +2182,17 @@ var classNaming = {
2357
2182
  if (property.computed) {
2358
2183
  return;
2359
2184
  }
2360
- if (
2361
- property.type === 'ExperimentalSpreadProperty' ||
2362
- property.type === 'SpreadElement'
2363
- ) {
2185
+ if (property.type === 'ExperimentalSpreadProperty' || property.type === 'SpreadElement') {
2364
2186
  return;
2365
2187
  }
2366
2188
  const className = property.key.value || property.key.name;
2367
2189
  if (!eslintUtils.isCamelCase(className)) {
2368
2190
  context.report({
2369
2191
  node: property,
2370
- message: `Class \`${className}\` must be camelCase in TSS.`
2192
+ messageId: 'camelCase',
2193
+ data: {
2194
+ className
2195
+ }
2371
2196
  });
2372
2197
  }
2373
2198
  });
@@ -2376,20 +2201,201 @@ var classNaming = {
2376
2201
  }
2377
2202
  };
2378
2203
 
2379
- var noColorValue = {
2204
+ var colors = {
2205
+ aliceblue: [240, 248, 255],
2206
+ antiquewhite: [250, 235, 215],
2207
+ aqua: [0, 255, 255],
2208
+ aquamarine: [127, 255, 212],
2209
+ azure: [240, 255, 255],
2210
+ beige: [245, 245, 220],
2211
+ bisque: [255, 228, 196],
2212
+ black: [0, 0, 0],
2213
+ blanchedalmond: [255, 235, 205],
2214
+ blue: [0, 0, 255],
2215
+ blueviolet: [138, 43, 226],
2216
+ brown: [165, 42, 42],
2217
+ burlywood: [222, 184, 135],
2218
+ cadetblue: [95, 158, 160],
2219
+ chartreuse: [127, 255, 0],
2220
+ chocolate: [210, 105, 30],
2221
+ coral: [255, 127, 80],
2222
+ cornflowerblue: [100, 149, 237],
2223
+ cornsilk: [255, 248, 220],
2224
+ crimson: [220, 20, 60],
2225
+ cyan: [0, 255, 255],
2226
+ darkblue: [0, 0, 139],
2227
+ darkcyan: [0, 139, 139],
2228
+ darkgoldenrod: [184, 134, 11],
2229
+ darkgray: [169, 169, 169],
2230
+ darkgreen: [0, 100, 0],
2231
+ darkgrey: [169, 169, 169],
2232
+ darkkhaki: [189, 183, 107],
2233
+ darkmagenta: [139, 0, 139],
2234
+ darkolivegreen: [85, 107, 47],
2235
+ darkorange: [255, 140, 0],
2236
+ darkorchid: [153, 50, 204],
2237
+ darkred: [139, 0, 0],
2238
+ darksalmon: [233, 150, 122],
2239
+ darkseagreen: [143, 188, 143],
2240
+ darkslateblue: [72, 61, 139],
2241
+ darkslategray: [47, 79, 79],
2242
+ darkslategrey: [47, 79, 79],
2243
+ darkturquoise: [0, 206, 209],
2244
+ darkviolet: [148, 0, 211],
2245
+ deeppink: [255, 20, 147],
2246
+ deepskyblue: [0, 191, 255],
2247
+ dimgray: [105, 105, 105],
2248
+ dimgrey: [105, 105, 105],
2249
+ dodgerblue: [30, 144, 255],
2250
+ firebrick: [178, 34, 34],
2251
+ floralwhite: [255, 250, 240],
2252
+ forestgreen: [34, 139, 34],
2253
+ fuchsia: [255, 0, 255],
2254
+ gainsboro: [220, 220, 220],
2255
+ ghostwhite: [248, 248, 255],
2256
+ gold: [255, 215, 0],
2257
+ goldenrod: [218, 165, 32],
2258
+ gray: [128, 128, 128],
2259
+ green: [0, 128, 0],
2260
+ greenyellow: [173, 255, 47],
2261
+ grey: [128, 128, 128],
2262
+ honeydew: [240, 255, 240],
2263
+ hotpink: [255, 105, 180],
2264
+ indianred: [205, 92, 92],
2265
+ indigo: [75, 0, 130],
2266
+ ivory: [255, 255, 240],
2267
+ khaki: [240, 230, 140],
2268
+ lavender: [230, 230, 250],
2269
+ lavenderblush: [255, 240, 245],
2270
+ lawngreen: [124, 252, 0],
2271
+ lemonchiffon: [255, 250, 205],
2272
+ lightblue: [173, 216, 230],
2273
+ lightcoral: [240, 128, 128],
2274
+ lightcyan: [224, 255, 255],
2275
+ lightgoldenrodyellow: [250, 250, 210],
2276
+ lightgray: [211, 211, 211],
2277
+ lightgreen: [144, 238, 144],
2278
+ lightgrey: [211, 211, 211],
2279
+ lightpink: [255, 182, 193],
2280
+ lightsalmon: [255, 160, 122],
2281
+ lightseagreen: [32, 178, 170],
2282
+ lightskyblue: [135, 206, 250],
2283
+ lightslategray: [119, 136, 153],
2284
+ lightslategrey: [119, 136, 153],
2285
+ lightsteelblue: [176, 196, 222],
2286
+ lightyellow: [255, 255, 224],
2287
+ lime: [0, 255, 0],
2288
+ limegreen: [50, 205, 50],
2289
+ linen: [250, 240, 230],
2290
+ magenta: [255, 0, 255],
2291
+ maroon: [128, 0, 0],
2292
+ mediumaquamarine: [102, 205, 170],
2293
+ mediumblue: [0, 0, 205],
2294
+ mediumorchid: [186, 85, 211],
2295
+ mediumpurple: [147, 112, 219],
2296
+ mediumseagreen: [60, 179, 113],
2297
+ mediumslateblue: [123, 104, 238],
2298
+ mediumspringgreen: [0, 250, 154],
2299
+ mediumturquoise: [72, 209, 204],
2300
+ mediumvioletred: [199, 21, 133],
2301
+ midnightblue: [25, 25, 112],
2302
+ mintcream: [245, 255, 250],
2303
+ mistyrose: [255, 228, 225],
2304
+ moccasin: [255, 228, 181],
2305
+ navajowhite: [255, 222, 173],
2306
+ navy: [0, 0, 128],
2307
+ oldlace: [253, 245, 230],
2308
+ olive: [128, 128, 0],
2309
+ olivedrab: [107, 142, 35],
2310
+ orange: [255, 165, 0],
2311
+ orangered: [255, 69, 0],
2312
+ orchid: [218, 112, 214],
2313
+ palegoldenrod: [238, 232, 170],
2314
+ palegreen: [152, 251, 152],
2315
+ paleturquoise: [175, 238, 238],
2316
+ palevioletred: [219, 112, 147],
2317
+ papayawhip: [255, 239, 213],
2318
+ peachpuff: [255, 218, 185],
2319
+ peru: [205, 133, 63],
2320
+ pink: [255, 192, 203],
2321
+ plum: [221, 160, 221],
2322
+ powderblue: [176, 224, 230],
2323
+ purple: [128, 0, 128],
2324
+ rebeccapurple: [102, 51, 153],
2325
+ red: [255, 0, 0],
2326
+ rosybrown: [188, 143, 143],
2327
+ royalblue: [65, 105, 225],
2328
+ saddlebrown: [139, 69, 19],
2329
+ salmon: [250, 128, 114],
2330
+ sandybrown: [244, 164, 96],
2331
+ seagreen: [46, 139, 87],
2332
+ seashell: [255, 245, 238],
2333
+ sienna: [160, 82, 45],
2334
+ silver: [192, 192, 192],
2335
+ skyblue: [135, 206, 235],
2336
+ slateblue: [106, 90, 205],
2337
+ slategray: [112, 128, 144],
2338
+ slategrey: [112, 128, 144],
2339
+ snow: [255, 250, 250],
2340
+ springgreen: [0, 255, 127],
2341
+ steelblue: [70, 130, 180],
2342
+ tan: [210, 180, 140],
2343
+ teal: [0, 128, 128],
2344
+ thistle: [216, 191, 216],
2345
+ tomato: [255, 99, 71],
2346
+ turquoise: [64, 224, 208],
2347
+ violet: [238, 130, 238],
2348
+ wheat: [245, 222, 179],
2349
+ white: [255, 255, 255],
2350
+ whitesmoke: [245, 245, 245],
2351
+ yellow: [255, 255, 0],
2352
+ yellowgreen: [154, 205, 50]
2353
+ };
2354
+
2355
+ var tssNoColorName = {
2380
2356
  meta: {
2381
- type: 'problem',
2357
+ type: 'suggestion',
2382
2358
  docs: {
2383
- description:
2384
- 'Enforce the use of color variables instead of color codes within TSS',
2359
+ description: 'Enforce the use of color variables instead of color name within TSS',
2385
2360
  recommended: true
2361
+ },
2362
+ messages: {
2363
+ disallowColorName: 'Disallowed color name. Use color from `@mui/material/colors` or `theme.palette`.'
2386
2364
  }
2387
2365
  },
2388
2366
  create: function (context) {
2389
- const parserOptions = context.parserOptions;
2390
- if (!parserOptions || !parserOptions.project) {
2391
- return {};
2367
+ return {
2368
+ CallExpression(node) {
2369
+ const stylesObj = getStyesObj(node);
2370
+ if (!stylesObj) {
2371
+ return;
2372
+ }
2373
+ function checkColorLiteral(value) {
2374
+ if (value.type === 'Literal' && typeof value.value === 'string' && Object.keys(colors).includes(value.value.toLowerCase())) {
2375
+ context.report({
2376
+ node: value,
2377
+ messageId: 'disallowColorName'
2378
+ });
2379
+ }
2380
+ }
2381
+ loopStylesObj(stylesObj, checkColorLiteral);
2382
+ }
2383
+ };
2384
+ }
2385
+ };
2386
+
2387
+ var tssNoColorValue = {
2388
+ meta: {
2389
+ type: 'problem',
2390
+ docs: {
2391
+ description: 'Enforce the use of color variables instead of color codes within TSS',
2392
+ recommended: true
2393
+ },
2394
+ messages: {
2395
+ preferMuiColor: 'Prefer use color from `@mui/material/colors` or `theme.palette`.'
2392
2396
  }
2397
+ },
2398
+ create: function (context) {
2393
2399
  return {
2394
2400
  CallExpression(node) {
2395
2401
  const stylesObj = getStyesObj(node);
@@ -2398,43 +2404,31 @@ var noColorValue = {
2398
2404
  }
2399
2405
  function checkColorLiteral(value) {
2400
2406
  if (value.type === 'Literal' && typeof value.value === 'string') {
2401
- const colorCodePattern =
2402
- /#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})|rgb\?\(\s*(\d{1,3}\s*,\s*){2}\d{1,3}(?:\s*,\s*\d*(?:\.\d+)?)?\s*\)/g;
2403
- const isColorCode = colorCodePattern.test(value.value);
2404
- if (isColorCode) {
2407
+ const colorCodePattern = /#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})|rgb\?\(\s*(\d{1,3}\s*,\s*){2}\d{1,3}(?:\s*,\s*\d*(?:\.\d+)?)?\s*\)/g;
2408
+ if (colorCodePattern.test(value.value)) {
2405
2409
  context.report({
2406
2410
  node: value,
2407
- message: 'Use color variables instead of color codes in TSS.'
2411
+ messageId: 'preferMuiColor'
2408
2412
  });
2409
2413
  }
2410
2414
  }
2411
2415
  }
2412
- function loopStylesObj(obj) {
2413
- if (obj && obj.type === 'ObjectExpression') {
2414
- obj.properties.forEach(property => {
2415
- if (property.type === 'Property' && property.value) {
2416
- if (property.value.type === 'ObjectExpression') {
2417
- loopStylesObj(property.value);
2418
- } else {
2419
- checkColorLiteral(property.value);
2420
- }
2421
- }
2422
- });
2423
- }
2424
- }
2425
- loopStylesObj(stylesObj);
2416
+ loopStylesObj(stylesObj, checkColorLiteral);
2426
2417
  }
2427
2418
  };
2428
2419
  }
2429
2420
  };
2430
2421
 
2431
- var unusedClasses = {
2422
+ var tssUnusedClasses = {
2432
2423
  meta: {
2433
2424
  type: 'suggestion',
2434
2425
  docs: {
2435
2426
  description: 'Disallow unused classes in tss',
2436
2427
  category: 'Best Practices',
2437
2428
  recommended: true
2429
+ },
2430
+ messages: {
2431
+ unusedClass: 'Class `{{ className }}` is unused in JSX'
2438
2432
  }
2439
2433
  },
2440
2434
  create: function rule(context) {
@@ -2450,20 +2444,14 @@ var unusedClasses = {
2450
2444
  if (property.computed) {
2451
2445
  return;
2452
2446
  }
2453
- if (
2454
- property.type === 'ExperimentalSpreadProperty' ||
2455
- property.type === 'SpreadElement'
2456
- ) {
2447
+ if (property.type === 'ExperimentalSpreadProperty' || property.type === 'SpreadElement') {
2457
2448
  return;
2458
2449
  }
2459
2450
  definedClasses[property.key.value || property.key.name] = property;
2460
2451
  });
2461
2452
  },
2462
2453
  MemberExpression(node) {
2463
- if (
2464
- node.object.type === 'Identifier' &&
2465
- node.object.name === 'classes'
2466
- ) {
2454
+ if (node.object.type === 'Identifier' && node.object.name === 'classes') {
2467
2455
  const whichClass = getBasicIdentifier(node.property);
2468
2456
  if (whichClass) {
2469
2457
  usedClasses[whichClass] = true;
@@ -2477,14 +2465,15 @@ var unusedClasses = {
2477
2465
  if (classIdentifier !== 'classes') {
2478
2466
  return;
2479
2467
  }
2480
- const { parent } = node;
2468
+ const {
2469
+ parent
2470
+ } = node;
2481
2471
  if (parent.type !== 'MemberExpression') {
2482
2472
  return;
2483
2473
  }
2484
2474
  if (
2485
- node.object.object &&
2486
- node.object.object.type !== 'ThisExpression'
2487
- ) {
2475
+ node.object.object &&
2476
+ node.object.object.type !== 'ThisExpression') {
2488
2477
  return;
2489
2478
  }
2490
2479
  const propsIdentifier = getBasicIdentifier(parent.object);
@@ -2507,7 +2496,10 @@ var unusedClasses = {
2507
2496
  if (!usedClasses[definedClassKey]) {
2508
2497
  context.report({
2509
2498
  node: definedClasses[definedClassKey],
2510
- message: `Class \`${definedClassKey}\` is unused`
2499
+ messageId: 'unusedClass',
2500
+ data: {
2501
+ className: definedClassKey
2502
+ }
2511
2503
  });
2512
2504
  }
2513
2505
  });
@@ -2516,177 +2508,27 @@ var unusedClasses = {
2516
2508
  }
2517
2509
  };
2518
2510
 
2519
- var noAsyncArrayMethods = {
2520
- meta: {
2521
- docs: {
2522
- description:
2523
- 'No async callback for Array methods forEach, map, filter, reduce, some, every, etc.',
2524
- category: 'Array',
2525
- recommended: true
2526
- },
2527
- fixable: undefined,
2528
- schema: []
2529
- },
2530
- create: function (context) {
2531
- return {
2532
- ExpressionStatement: function (node) {
2533
- const notAllowedArrayMethods = [
2534
- 'forEach',
2535
- 'filter',
2536
- 'some',
2537
- 'every',
2538
- 'map',
2539
- 'reduce',
2540
- 'reduceRight',
2541
- 'flatMap',
2542
- 'find',
2543
- 'findIndex',
2544
- 'findLast',
2545
- 'findLastIndex'
2546
- ];
2547
- const { callee } = node.expression;
2548
- if (!callee || !callee.property || !callee.property.name) {
2549
- return;
2550
- }
2551
- if (notAllowedArrayMethods.includes(callee.property.name)) {
2552
- const functionArguments = node.expression.arguments.find(n => {
2553
- return ['ArrowFunctionExpression', 'FunctionExpression'].includes(
2554
- n.type
2555
- );
2556
- });
2557
- if (functionArguments && functionArguments.async) {
2558
- context.report({
2559
- node,
2560
- message: `No async function in method '${callee.property.name}'`
2561
- });
2562
- }
2563
- }
2564
- }
2565
- };
2566
- }
2567
- };
2568
-
2569
- var noThenCatchFinally = {
2570
- meta: {
2571
- type: 'suggestion',
2572
- docs: {
2573
- description:
2574
- 'Disallow the use of then()/catch()/finally() when invoking specific functions.'
2575
- },
2576
- schema: [
2577
- {
2578
- type: 'object',
2579
- properties: {
2580
- restrictedFunctions: {
2581
- type: 'array',
2582
- uniqueItems: true,
2583
- items: { type: 'string' }
2584
- }
2585
- }
2586
- }
2587
- ],
2588
- messages: {
2589
- forbiddenThenCatchFinally: `then()/catch()/finally() is forbidden when invoke {{ name }}().`
2590
- }
2591
- },
2592
- create(context) {
2593
- const configuration = context.options[0] || {};
2594
- const restrictedFunctions = configuration.restrictedFunctions || [];
2595
- function isTopLevelScoped() {
2596
- return context.getScope().block.type === 'Program';
2597
- }
2598
- function isThenCatchFinally(node) {
2599
- return (
2600
- node.property &&
2601
- (node.property.name === 'then' ||
2602
- node.property.name === 'catch' ||
2603
- node.property.name === 'finally')
2604
- );
2605
- }
2606
- return {
2607
- 'CallExpression > MemberExpression.callee'(node) {
2608
- if (isTopLevelScoped()) {
2609
- return;
2610
- }
2611
- if (!isThenCatchFinally(node)) {
2612
- return;
2613
- }
2614
- const callExpression = node.object;
2615
- if (
2616
- callExpression.type === 'CallExpression' &&
2617
- callExpression.callee.type === 'Identifier' &&
2618
- restrictedFunctions.includes(callExpression.callee.name)
2619
- ) {
2620
- context.report({
2621
- node: node.property,
2622
- messageId: 'forbiddenThenCatchFinally',
2623
- data: {
2624
- name: callExpression.callee.name
2625
- }
2626
- });
2627
- }
2628
- }
2629
- };
2630
- }
2631
- };
2632
-
2633
- var noUnnecessaryTemplateLiterals = {
2634
- meta: {
2635
- type: 'problem',
2636
- docs: {
2637
- description: 'Check if a template string contains only one ${}',
2638
- recommended: true
2639
- },
2640
- fixable: 'code',
2641
- schema: [],
2642
- messages: {
2643
- unnecessaryTemplateString:
2644
- 'Unnecessary template string with only one ${}.'
2645
- }
2646
- },
2647
- create(context) {
2648
- return {
2649
- TemplateLiteral(node) {
2650
- const code = context.sourceCode.getText(node);
2651
- if (
2652
- code.startsWith('`${') &&
2653
- code.endsWith('}`') &&
2654
- code.split('${').length === 2
2655
- ) {
2656
- context.report({
2657
- node,
2658
- messageId: 'unnecessaryTemplateString',
2659
- fix(fixer) {
2660
- return fixer.replaceText(
2661
- node,
2662
- code.substring(3, code.length - 2)
2663
- );
2664
- }
2665
- });
2666
- }
2667
- }
2668
- };
2669
- }
2670
- };
2671
-
2672
2511
  var ruleFiles = /*#__PURE__*/Object.freeze({
2673
2512
  __proto__: null,
2674
- rules_import_enforce_icon_alias: enforceIconAlias,
2675
- rules_import_monorepo: monorepo,
2676
- rules_intl_id_missing: idMissing,
2677
- rules_intl_id_prefix: idPrefix,
2678
- rules_intl_id_unused: idUnused,
2679
- rules_intl_no_default: noDefault,
2680
- rules_react_better_exhaustive_deps: betterExhaustiveDeps,
2681
- rules_react_hook_use_ref: hookUseRef,
2682
- rules_react_prefer_named_property_access: preferNamedPropertyAccess,
2683
- rules_react_prefer_sx_prop: preferSxProp,
2684
- rules_tss_class_naming: classNaming,
2685
- rules_tss_no_color_value: noColorValue,
2686
- rules_tss_unused_classes: unusedClasses,
2687
- rules_unprefixed_no_async_array_methods: noAsyncArrayMethods,
2688
- rules_unprefixed_no_then_catch_finally: noThenCatchFinally,
2689
- rules_unprefixed_no_unnecessary_template_literals: noUnnecessaryTemplateLiterals
2513
+ rules_enforce_mui_icon_alias: enforceMuiIconAlias,
2514
+ rules_import_monorepo: importMonorepo,
2515
+ rules_intl_id_missing: intlIdMissing,
2516
+ rules_intl_id_naming: intlIdNaming,
2517
+ rules_intl_id_prefix: intlIdPrefix,
2518
+ rules_intl_id_unused: intlIdUnused,
2519
+ rules_intl_no_default: intlNoDefault,
2520
+ rules_no_async_array_methods: noAsyncArrayMethods,
2521
+ rules_no_import_css: noImportCss,
2522
+ rules_no_then_catch_finally: noThenCatchFinally,
2523
+ rules_no_unnecessary_template_literals: noUnnecessaryTemplateLiterals,
2524
+ rules_react_better_exhaustive_deps: reactBetterExhaustiveDeps,
2525
+ rules_react_hook_use_ref: reactHookUseRef,
2526
+ rules_react_prefer_named_property_access: reactPreferNamedPropertyAccess,
2527
+ rules_react_prefer_sx_prop: reactPreferSxProp,
2528
+ rules_tss_class_naming: tssClassNaming,
2529
+ rules_tss_no_color_name: tssNoColorName,
2530
+ rules_tss_no_color_value: tssNoColorValue,
2531
+ rules_tss_unused_classes: tssUnusedClasses
2690
2532
  });
2691
2533
 
2692
2534
  const plugin = {
@@ -2704,13 +2546,12 @@ const plugin = {
2704
2546
  }
2705
2547
  };
2706
2548
  Object.keys(ruleFiles).forEach(key => {
2707
- const ruleKey = key.replace(/^rules_/, '').replace(/^unprefixed_/, '');
2549
+ const ruleKey = key.replace(/^rules_/, '');
2708
2550
  const finalKey = ruleKey.replace(/_/g, '-');
2709
2551
  const rule = ruleFiles[key];
2710
2552
  plugin.rules[finalKey] = rule;
2711
2553
  if (rule.meta && rule.meta.docs && rule.meta.docs.recommended) {
2712
- plugin.configs.recommended.rules[`@agilebot/${finalKey}`] =
2713
- rule.meta.type === 'suggestion' ? 'warn' : 'error';
2554
+ plugin.configs.recommended.rules["@agilebot/".concat(finalKey)] = rule.meta.type === 'suggestion' ? 'warn' : 'error';
2714
2555
  }
2715
2556
  });
2716
2557