@borela-tech/eslint-config 2.3.0 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -82,7 +82,7 @@ function checkArray(sourceCode, context, node2) {
82
82
  node: elements[0]
83
83
  });
84
84
  }
85
- const messageIds$c = {
85
+ const messageIds$d = {
86
86
  arrayItemsOnNewLine: "arrayItemsOnNewLine"
87
87
  };
88
88
  const arrayItemsLineBreak = {
@@ -99,7 +99,7 @@ const arrayItemsLineBreak = {
99
99
  description: "Enforce each array item to be on its own line when the array expression exceeds a configurable maximum line length."
100
100
  },
101
101
  fixable: "code",
102
- messages: messageIds$c,
102
+ messages: messageIds$d,
103
103
  schema: [{
104
104
  additionalProperties: false,
105
105
  properties: {
@@ -305,7 +305,7 @@ function checkObjectExpression(sourceCode, context, node2) {
305
305
  checkClosingBrace(sourceCode, context, node2, closingBrace);
306
306
  checkNestedObjects(sourceCode, context, node2, checkObjectExpression);
307
307
  }
308
- const messageIds$b = {
308
+ const messageIds$c = {
309
309
  braceOnPropertyLine: "Opening brace should be on its own line",
310
310
  propertiesOnSameLine: "Multi-line objects must have each property on its own line"
311
311
  };
@@ -323,7 +323,7 @@ const braceStyleObjectLiteral = {
323
323
  description: "Enforce consistent brace positioning for object literals."
324
324
  },
325
325
  fixable: "code",
326
- messages: messageIds$b,
326
+ messages: messageIds$c,
327
327
  schema: [{
328
328
  additionalProperties: false,
329
329
  properties: {},
@@ -378,7 +378,7 @@ function isBracketOnOwnLine(sourceCode, openingBracket) {
378
378
  );
379
379
  return textBetween.includes("\n");
380
380
  }
381
- const messageIds$a = {
381
+ const messageIds$b = {
382
382
  compactItems: "Array items should be compact when the array spans multiple lines."
383
383
  };
384
384
  const compactArrayItems = {
@@ -422,7 +422,7 @@ const compactArrayItems = {
422
422
  description: "Enforce arrays with multiline items to have a compact, inline bracket style."
423
423
  },
424
424
  fixable: "code",
425
- messages: messageIds$a,
425
+ messages: messageIds$b,
426
426
  schema: [],
427
427
  type: "layout"
428
428
  }
@@ -473,11 +473,11 @@ function getExportedNames(node2) {
473
473
  function stripExtension(filename) {
474
474
  return path.basename(filename, path.extname(filename));
475
475
  }
476
- function isExempt$1(filename) {
476
+ function isExempt$2(filename) {
477
477
  const name = stripExtension(filename);
478
478
  return name === "index" || name.endsWith(".test") || name.endsWith(".spec") || name.endsWith(".config");
479
479
  }
480
- const messageIds$9 = {
480
+ const messageIds$a = {
481
481
  filenameMismatch: "File name must be '{{expectedName}}' instead of '{{currentName}}'."
482
482
  };
483
483
  const exportFilenameMatch = {
@@ -486,7 +486,7 @@ const exportFilenameMatch = {
486
486
  const baseName = path.basename(fileName);
487
487
  const ext = path.extname(baseName);
488
488
  const fileNameWithoutExt = baseName.slice(0, -ext.length);
489
- if (isExempt$1(fileName))
489
+ if (isExempt$2(fileName))
490
490
  return {};
491
491
  const exportNames = [];
492
492
  return {
@@ -515,7 +515,7 @@ const exportFilenameMatch = {
515
515
  docs: {
516
516
  description: "Enforce filename matches the single named export."
517
517
  },
518
- messages: messageIds$9,
518
+ messages: messageIds$a,
519
519
  schema: [],
520
520
  type: "suggestion"
521
521
  }
@@ -685,7 +685,7 @@ function checkCall(sourceCode, context, node2) {
685
685
  else
686
686
  checkMultilineArgs(sourceCode, context, args, maxLength);
687
687
  }
688
- const messageIds$8 = {
688
+ const messageIds$9 = {
689
689
  exceedsMaxLength: "Refactor this function call as it exceeds {{maxLength}} characters",
690
690
  multipleOnSameLine: "Each argument must be on its own line"
691
691
  };
@@ -706,7 +706,7 @@ const functionCallArgumentLineBreak = {
706
706
  description: "Enforce each function call argument to be on its own line when line exceeds max length."
707
707
  },
708
708
  fixable: "code",
709
- messages: messageIds$8,
709
+ messages: messageIds$9,
710
710
  schema: [{
711
711
  additionalProperties: false,
712
712
  properties: {
@@ -818,7 +818,7 @@ function getFunctionExpressionName(node2) {
818
818
  return nameFromMethod;
819
819
  return null;
820
820
  }
821
- function getFunctionName(node2) {
821
+ function getFunctionName$1(node2) {
822
822
  if (node2.type === "FunctionDeclaration" && node2.id?.name)
823
823
  return node2.id.name;
824
824
  if (node2.type === "FunctionExpression")
@@ -827,7 +827,7 @@ function getFunctionName(node2) {
827
827
  return getArrowFunctionExpressionName(node2);
828
828
  return null;
829
829
  }
830
- const messageIds$7 = {
830
+ const messageIds$8 = {
831
831
  tooHighCognitiveComplexity: "Function '{{name}}' has cognitive complexity of {{actual}} (max: {{max}}). Consider extracting sub-functions.",
832
832
  tooHighCognitiveComplexityAnonymous: "Anonymous function has cognitive complexity of {{actual}} (max: {{max}}). Consider extracting sub-functions."
833
833
  };
@@ -839,7 +839,7 @@ const functionCognitiveComplexity = {
839
839
  function checkFunction2(node2) {
840
840
  const complexity = calculateCognitiveComplexity(node2);
841
841
  if (complexity > maxCognitiveComplexity) {
842
- const name = getFunctionName(node2);
842
+ const name = getFunctionName$1(node2);
843
843
  if (name) {
844
844
  context.report({
845
845
  data: {
@@ -878,7 +878,7 @@ const functionCognitiveComplexity = {
878
878
  docs: {
879
879
  description: "Enforce cognitive complexity threshold for functions."
880
880
  },
881
- messages: messageIds$7,
881
+ messages: messageIds$8,
882
882
  schema: [{
883
883
  additionalProperties: false,
884
884
  properties: {
@@ -1025,7 +1025,7 @@ function checkFunction$1(sourceCode, context, node2) {
1025
1025
  else
1026
1026
  checkMultilineParams(sourceCode, context, params, parens, maxLength);
1027
1027
  }
1028
- const messageIds$6 = {
1028
+ const messageIds$7 = {
1029
1029
  exceedsMaxLength: "Refactor this function signature as it exceeds {{maxLength}} characters",
1030
1030
  multipleOnSameLine: "Each parameter must be on its own line"
1031
1031
  };
@@ -1060,7 +1060,7 @@ const functionParameterLineBreak = {
1060
1060
  description: "Enforce each function parameter to be on its own line when line exceeds max length."
1061
1061
  },
1062
1062
  fixable: "code",
1063
- messages: messageIds$6,
1063
+ messages: messageIds$7,
1064
1064
  schema: [{
1065
1065
  additionalProperties: false,
1066
1066
  properties: {
@@ -1382,7 +1382,7 @@ function checkInterface(sourceCode, context, node2) {
1382
1382
  else
1383
1383
  checkMultilineMembers(sourceCode, context, body.body, maxLength);
1384
1384
  }
1385
- const messageIds$5 = {
1385
+ const messageIds$6 = {
1386
1386
  exceedsMaxLength: "Interface line exceeds {{maxLength}} characters",
1387
1387
  multipleOnSameLine: "Interface members should each be on their own line when line exceeds {{maxLength}} characters"
1388
1388
  };
@@ -1400,7 +1400,7 @@ const interfacePropertyLineBreak = {
1400
1400
  description: "Enforce each interface member to be on its own line when line exceeds max length."
1401
1401
  },
1402
1402
  fixable: "code",
1403
- messages: messageIds$5,
1403
+ messages: messageIds$6,
1404
1404
  schema: [{
1405
1405
  additionalProperties: false,
1406
1406
  properties: {
@@ -1450,7 +1450,7 @@ function handleTSTypeAliasDeclaration(node2, types) {
1450
1450
  if (isTopLevel(node2) && node2.id?.name)
1451
1451
  types.add(node2.id.name);
1452
1452
  }
1453
- function isExempt(filename) {
1453
+ function isExempt$1(filename) {
1454
1454
  const name = path.basename(filename, path.extname(filename));
1455
1455
  const isTest = name.endsWith(".test");
1456
1456
  const isSpec = name.endsWith(".spec");
@@ -1460,13 +1460,13 @@ function isExempt(filename) {
1460
1460
  function isExportedDeclaration(parent) {
1461
1461
  return parent?.type === "ExportNamedDeclaration";
1462
1462
  }
1463
- const messageIds$4 = {
1463
+ const messageIds$5 = {
1464
1464
  tooManyDeclarations: "File has {{count}} declarations. Put each function/class/const/type declaration in its own file."
1465
1465
  };
1466
1466
  const maxDeclarationsPerFile = {
1467
1467
  create(context) {
1468
1468
  const filename = context.filename;
1469
- if (isExempt(filename))
1469
+ if (isExempt$1(filename))
1470
1470
  return {};
1471
1471
  const functions = /* @__PURE__ */ new Set();
1472
1472
  const types = /* @__PURE__ */ new Set();
@@ -1524,7 +1524,7 @@ const maxDeclarationsPerFile = {
1524
1524
  docs: {
1525
1525
  description: "Enforce single top-level declaration per file."
1526
1526
  },
1527
- messages: messageIds$4,
1527
+ messages: messageIds$5,
1528
1528
  schema: [],
1529
1529
  type: "suggestion"
1530
1530
  }
@@ -1582,6 +1582,306 @@ const multilineUnionTypeAliases = {
1582
1582
  type: "layout"
1583
1583
  }
1584
1584
  };
1585
+ function isExempt(name) {
1586
+ return name.startsWith("_");
1587
+ }
1588
+ function isPascalCase(name) {
1589
+ if (!/^[A-Z]/.test(name))
1590
+ return false;
1591
+ return /^[A-Z][\dA-Za-z]*$/.test(name);
1592
+ }
1593
+ function isSeparator(char) {
1594
+ return char === "_" || char === "-" || char === " ";
1595
+ }
1596
+ function isWordBoundary(char, currentWord, prevChar, nextChar) {
1597
+ if (!currentWord)
1598
+ return false;
1599
+ const isUpper = /[A-Z]/.test(char);
1600
+ const prevIsUpper = /[A-Z]/.test(prevChar);
1601
+ const nextIsLower = /[a-z]/.test(nextChar);
1602
+ if (isUpper) {
1603
+ const isStartOfNewWord = !prevIsUpper || prevIsUpper && nextIsLower;
1604
+ return isStartOfNewWord;
1605
+ }
1606
+ return false;
1607
+ }
1608
+ function capitalize(word) {
1609
+ return word.charAt(0).toUpperCase() + word.slice(1);
1610
+ }
1611
+ function wordsToCamelCase(words) {
1612
+ if (words.length === 0)
1613
+ return "";
1614
+ if (words.length === 1)
1615
+ return words[0].toLowerCase();
1616
+ const firstWord = words[0].toLowerCase();
1617
+ const restWords = words.slice(1).map(capitalize);
1618
+ return firstWord + restWords.join("");
1619
+ }
1620
+ function toCamelCase(name) {
1621
+ const words = [];
1622
+ let currentWord = "";
1623
+ for (let i = 0; i < name.length; i++) {
1624
+ const char = name[i];
1625
+ const prevChar = i > 0 ? name[i - 1] : "";
1626
+ const nextChar = i < name.length - 1 ? name[i + 1] : "";
1627
+ if (isSeparator(char)) {
1628
+ if (currentWord) {
1629
+ words.push(currentWord.toLowerCase());
1630
+ currentWord = "";
1631
+ }
1632
+ continue;
1633
+ }
1634
+ if (isWordBoundary(char, currentWord, prevChar, nextChar)) {
1635
+ words.push(currentWord.toLowerCase());
1636
+ currentWord = char;
1637
+ continue;
1638
+ }
1639
+ currentWord += char;
1640
+ }
1641
+ if (currentWord)
1642
+ words.push(currentWord.toLowerCase());
1643
+ return wordsToCamelCase(words);
1644
+ }
1645
+ function toPascalCase$1(name) {
1646
+ const camelCase = toCamelCase(name);
1647
+ return camelCase.charAt(0).toUpperCase() + camelCase.slice(1);
1648
+ }
1649
+ function checkClass(id, context) {
1650
+ if (!id)
1651
+ return;
1652
+ const name = id.name;
1653
+ if (isExempt(name))
1654
+ return;
1655
+ if (!isPascalCase(name)) {
1656
+ context.report({
1657
+ data: {
1658
+ name,
1659
+ type: "Class"
1660
+ },
1661
+ fix(fixer) {
1662
+ return fixer.replaceText(id, toPascalCase$1(name));
1663
+ },
1664
+ messageId: "notPascalCase",
1665
+ node: id
1666
+ });
1667
+ }
1668
+ }
1669
+ function checkNamedEntity(name, node2, type, context) {
1670
+ if (isExempt(name))
1671
+ return;
1672
+ if (!isPascalCase(name)) {
1673
+ context.report({
1674
+ data: { name, type },
1675
+ fix(fixer) {
1676
+ return fixer.replaceText(node2, toPascalCase$1(name));
1677
+ },
1678
+ messageId: "notPascalCase",
1679
+ node: node2
1680
+ });
1681
+ }
1682
+ }
1683
+ function isCamelCase(name) {
1684
+ if (!/^[a-z]/.test(name))
1685
+ return false;
1686
+ return /^[a-z][\dA-Za-z]*$/.test(name);
1687
+ }
1688
+ function isUpperCase(name) {
1689
+ return /^[A-Z][\dA-Z_]*$/.test(name);
1690
+ }
1691
+ function checkConstant(name, node2, context) {
1692
+ if (!isCamelCase(name) && !isUpperCase(name)) {
1693
+ context.report({
1694
+ data: { name },
1695
+ messageId: "notUpperCase",
1696
+ node: node2
1697
+ });
1698
+ }
1699
+ }
1700
+ function checkVariable(name, node2, context) {
1701
+ if (!isCamelCase(name)) {
1702
+ context.report({
1703
+ data: { name },
1704
+ fix(fixer) {
1705
+ return fixer.replaceText(node2, toCamelCase(name));
1706
+ },
1707
+ messageId: "notCamelCase",
1708
+ node: node2
1709
+ });
1710
+ }
1711
+ }
1712
+ function isFunction(init) {
1713
+ if (!init)
1714
+ return false;
1715
+ return init.type === "FunctionExpression" || init.type === "ArrowFunctionExpression";
1716
+ }
1717
+ function checkVariableDeclarator(node2, context) {
1718
+ const id = node2.id;
1719
+ const name = id.name;
1720
+ if (isExempt(name))
1721
+ return;
1722
+ if (isFunction(node2.init))
1723
+ return;
1724
+ const parent = node2.parent;
1725
+ if (parent?.type !== "VariableDeclaration")
1726
+ return;
1727
+ const kind = parent.kind;
1728
+ if (kind === "const")
1729
+ checkConstant(name, id, context);
1730
+ else
1731
+ checkVariable(name, id, context);
1732
+ }
1733
+ function getFunctionName(node2, parent) {
1734
+ if (node2.type === "FunctionDeclaration" && node2.id)
1735
+ return node2.id.name;
1736
+ if ((node2.type === "FunctionExpression" || node2.type === "ArrowFunctionExpression") && parent?.type === "VariableDeclarator" && parent.id.type === "Identifier")
1737
+ return parent.id.name;
1738
+ return null;
1739
+ }
1740
+ function getReturnTypeText(sourceCode, node2) {
1741
+ if (!node2.returnType)
1742
+ return void 0;
1743
+ return sourceCode.getText(node2.returnType.typeAnnotation);
1744
+ }
1745
+ function isReactComponent(returnTypeText) {
1746
+ if (!returnTypeText)
1747
+ return false;
1748
+ const patterns = [
1749
+ "JSX.Element",
1750
+ "React.JSX.Element",
1751
+ "ReactElement",
1752
+ "ReactNode"
1753
+ ];
1754
+ return patterns.some((pattern) => returnTypeText.includes(pattern));
1755
+ }
1756
+ const messageIds$4 = {
1757
+ notCamelCase: 'Function "{{name}}" should use camelCase',
1758
+ notPascalCase: '{{type}} "{{name}}" should use PascalCase',
1759
+ notUpperCase: 'Constant "{{name}}" should use UPPER_CASE'
1760
+ };
1761
+ function getFunctionIdentifierNodeForFixer(node2, parent) {
1762
+ if (node2.type === "FunctionDeclaration")
1763
+ return node2.id;
1764
+ if (parent?.type === "VariableDeclarator")
1765
+ return parent.id;
1766
+ return null;
1767
+ }
1768
+ function getFunctionNameForFixer(node2, parent) {
1769
+ if (node2.type === "FunctionDeclaration" && node2.id)
1770
+ return node2.id.name;
1771
+ if (parent?.type === "VariableDeclarator" && parent.id.type === "Identifier")
1772
+ return parent.id.name;
1773
+ return "";
1774
+ }
1775
+ function createFunctionFixer(node2, parent, convert) {
1776
+ return (fixer) => {
1777
+ const fixedName = convert(getFunctionNameForFixer(node2, parent));
1778
+ const identifierNode = getFunctionIdentifierNodeForFixer(node2, parent);
1779
+ if (identifierNode)
1780
+ return fixer.replaceText(identifierNode, fixedName);
1781
+ return null;
1782
+ };
1783
+ }
1784
+ function getFunctionReportNode(node2, parent) {
1785
+ if (node2.type === "FunctionDeclaration")
1786
+ return node2;
1787
+ return parent ?? node2;
1788
+ }
1789
+ function reportComponentViolation(node2, parent, name, context) {
1790
+ if (isPascalCase(name))
1791
+ return;
1792
+ context.report({
1793
+ data: {
1794
+ name,
1795
+ type: "React component"
1796
+ },
1797
+ fix: createFunctionFixer(node2, parent, toPascalCase$1),
1798
+ messageId: "notPascalCase",
1799
+ node: getFunctionReportNode(node2, parent)
1800
+ });
1801
+ }
1802
+ function reportFunctionViolation(node2, parent, name, context) {
1803
+ if (isCamelCase(name))
1804
+ return;
1805
+ context.report({
1806
+ data: { name },
1807
+ fix: createFunctionFixer(node2, parent, toCamelCase),
1808
+ messageId: "notCamelCase",
1809
+ node: getFunctionReportNode(node2, parent)
1810
+ });
1811
+ }
1812
+ const namingConvention = {
1813
+ create(context) {
1814
+ const sourceCode = context.sourceCode ?? context.getSourceCode();
1815
+ return {
1816
+ ArrowFunctionExpression(node2) {
1817
+ checkFunction2(node2, node2.parent);
1818
+ },
1819
+ ClassDeclaration(node2) {
1820
+ checkClass(node2.id, context);
1821
+ },
1822
+ ClassExpression(node2) {
1823
+ checkClass(node2.id, context);
1824
+ },
1825
+ FunctionDeclaration(node2) {
1826
+ checkFunction2(node2);
1827
+ },
1828
+ FunctionExpression(node2) {
1829
+ checkFunction2(node2, node2.parent);
1830
+ },
1831
+ TSEnumDeclaration(node2) {
1832
+ checkNamedEntity(
1833
+ node2.id.name,
1834
+ node2.id,
1835
+ "Enum",
1836
+ context
1837
+ );
1838
+ },
1839
+ TSInterfaceDeclaration(node2) {
1840
+ checkNamedEntity(
1841
+ node2.id.name,
1842
+ node2.id,
1843
+ "Interface",
1844
+ context
1845
+ );
1846
+ },
1847
+ TSTypeAliasDeclaration(node2) {
1848
+ if (node2.id.type !== "Identifier")
1849
+ return;
1850
+ checkNamedEntity(
1851
+ node2.id.name,
1852
+ node2.id,
1853
+ "Type",
1854
+ context
1855
+ );
1856
+ },
1857
+ VariableDeclarator(node2) {
1858
+ if (node2.id.type !== "Identifier")
1859
+ return;
1860
+ checkVariableDeclarator(node2, context);
1861
+ }
1862
+ };
1863
+ function checkFunction2(node2, parent) {
1864
+ const name = getFunctionName(node2, parent);
1865
+ if (!name || isExempt(name))
1866
+ return;
1867
+ const returnTypeText = getReturnTypeText(sourceCode, node2);
1868
+ const isComponent = isReactComponent(returnTypeText);
1869
+ if (isComponent)
1870
+ reportComponentViolation(node2, parent, name, context);
1871
+ else
1872
+ reportFunctionViolation(node2, parent, name, context);
1873
+ }
1874
+ },
1875
+ meta: {
1876
+ docs: {
1877
+ description: "Enforce consistent naming conventions."
1878
+ },
1879
+ fixable: "code",
1880
+ messages: messageIds$4,
1881
+ schema: [],
1882
+ type: "suggestion"
1883
+ }
1884
+ };
1585
1885
  function checkTypeParameters(node2, containsInline) {
1586
1886
  if (!("typeParameters" in node2) || !node2.typeParameters)
1587
1887
  return null;
@@ -2227,7 +2527,7 @@ const messageIds$2 = {
2227
2527
  const oneExportPerFile = {
2228
2528
  create(context) {
2229
2529
  const filename = context.filename;
2230
- if (isExempt$1(filename))
2530
+ if (isExempt$2(filename))
2231
2531
  return {};
2232
2532
  let exportCount = 0;
2233
2533
  return {
@@ -3219,6 +3519,7 @@ const customRules = {
3219
3519
  "interface-property-line-break": interfacePropertyLineBreak,
3220
3520
  "max-declarations-per-file": maxDeclarationsPerFile,
3221
3521
  "multiline-union-type-aliases": multilineUnionTypeAliases,
3522
+ "naming-convention": namingConvention,
3222
3523
  "no-inline-object-types": noInlineObjectTypes,
3223
3524
  "no-unnecessary-braces": noUnnecessaryBraces,
3224
3525
  "object-property-line-break": objectPropertyLineBreak,
@@ -3263,6 +3564,7 @@ const customRules = {
3263
3564
  ],
3264
3565
  "@borela-tech/max-declarations-per-file": "error",
3265
3566
  "@borela-tech/multiline-union-type-aliases": "error",
3567
+ "@borela-tech/naming-convention": "error",
3266
3568
  "@borela-tech/no-inline-object-types": "error",
3267
3569
  "@borela-tech/no-unnecessary-braces": "error",
3268
3570
  "@borela-tech/object-property-line-break": "error",
@@ -3443,32 +3745,6 @@ const typescriptRules = {
3443
3745
  { fixStyle: "separate-type-imports" }
3444
3746
  ],
3445
3747
  "@typescript-eslint/explicit-function-return-type": "error",
3446
- "@typescript-eslint/naming-convention": ["error", {
3447
- format: ["camelCase"],
3448
- leadingUnderscore: "allow",
3449
- selector: "default",
3450
- trailingUnderscore: "allow"
3451
- }, {
3452
- format: ["camelCase", "PascalCase"],
3453
- selector: "import"
3454
- }, {
3455
- format: ["camelCase", "UPPER_CASE"],
3456
- leadingUnderscore: "allow",
3457
- selector: "variable",
3458
- trailingUnderscore: "allow"
3459
- }, {
3460
- format: ["PascalCase"],
3461
- selector: "typeLike"
3462
- }, {
3463
- format: null,
3464
- selector: "property"
3465
- }, {
3466
- format: null,
3467
- selector: "objectLiteralProperty"
3468
- }, {
3469
- format: null,
3470
- selector: "objectLiteralMethod"
3471
- }],
3472
3748
  "@typescript-eslint/no-empty-function": "off",
3473
3749
  "@typescript-eslint/no-unused-vars": ["error", {
3474
3750
  argsIgnorePattern: "^_",
@@ -3594,7 +3870,6 @@ const unicornRules = {
3594
3870
  "unicorn/no-useless-promise-resolve-reject": "error",
3595
3871
  "unicorn/no-useless-spread": "error",
3596
3872
  "unicorn/no-useless-switch-case": "error",
3597
- "unicorn/no-useless-undefined": "error",
3598
3873
  "unicorn/number-literal-case": "error",
3599
3874
  "unicorn/numeric-separators-style": "error",
3600
3875
  "unicorn/prefer-array-find": "error",