eslint-plugin-sweepit 0.0.1 → 0.0.2

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.cjs CHANGED
@@ -1470,6 +1470,13 @@ var rule13 = {
1470
1470
  var no_object_props_default = rule13;
1471
1471
 
1472
1472
  // src/rules/no-array-props.ts
1473
+ function getTypeName(node) {
1474
+ if (!node) return null;
1475
+ const typedNode = node;
1476
+ if (typedNode.type === "Identifier" && typedNode.name) return typedNode.name;
1477
+ if (typedNode.type === "TSQualifiedName" && typedNode.right?.name) return typedNode.right.name;
1478
+ return null;
1479
+ }
1473
1480
  var rule14 = {
1474
1481
  meta: {
1475
1482
  type: "suggestion",
@@ -1486,12 +1493,56 @@ var rule14 = {
1486
1493
  const parserServices = context.sourceCode.parserServices ?? context.parserServices;
1487
1494
  const checker = parserServices?.program?.getTypeChecker();
1488
1495
  const hasTypeInformation = Boolean(checker && parserServices?.esTreeNodeToTSNodeMap);
1496
+ const arrayTypedIdentifiers = /* @__PURE__ */ new Set();
1497
+ const arrayReturningFunctions = /* @__PURE__ */ new Set();
1498
+ const localTypeAliases = /* @__PURE__ */ new Map();
1499
+ function isArrayLikeTypeText(typeText) {
1500
+ return typeText.endsWith("[]") || typeText.startsWith("readonly ") || typeText.startsWith("Array<") || typeText.startsWith("ReadonlyArray<") || typeText.startsWith("[") || typeText.startsWith("readonly [");
1501
+ }
1502
+ function isArrayLikeTypeNode(typeNode, seenAliases) {
1503
+ if (!typeNode) return false;
1504
+ const typedNode = typeNode;
1505
+ if (typedNode.type === "TSArrayType" || typedNode.type === "TSTupleType") return true;
1506
+ if (typedNode.type === "TSParenthesizedType" || typedNode.type === "TSOptionalType") {
1507
+ return isArrayLikeTypeNode(typedNode.typeAnnotation, seenAliases);
1508
+ }
1509
+ if (typedNode.type === "TSTypeOperator") {
1510
+ return isArrayLikeTypeNode(typedNode.typeAnnotation, seenAliases);
1511
+ }
1512
+ if (typedNode.type === "TSUnionType" || typedNode.type === "TSIntersectionType") {
1513
+ return (typedNode.types ?? []).some((entry) => isArrayLikeTypeNode(entry, seenAliases));
1514
+ }
1515
+ if (typedNode.type === "TSTypeReference") {
1516
+ const typeName = getTypeName(typedNode.typeName);
1517
+ if (!typeName) return false;
1518
+ if (typeName === "Array" || typeName === "ReadonlyArray") return true;
1519
+ if (seenAliases.has(typeName)) return false;
1520
+ const aliasType = localTypeAliases.get(typeName);
1521
+ if (!aliasType) return false;
1522
+ const nextSeenAliases = new Set(seenAliases);
1523
+ nextSeenAliases.add(typeName);
1524
+ return isArrayLikeTypeNode(aliasType, nextSeenAliases);
1525
+ }
1526
+ return false;
1527
+ }
1528
+ function expressionHasArrayShapeByAst(expression) {
1529
+ const typedExpression = expression;
1530
+ if (typedExpression.type === "Identifier" && typedExpression.name) {
1531
+ return arrayTypedIdentifiers.has(typedExpression.name);
1532
+ }
1533
+ if (typedExpression.type === "CallExpression" && typedExpression.callee) {
1534
+ const callee = typedExpression.callee;
1535
+ return callee.type === "Identifier" && Boolean(callee.name && arrayReturningFunctions.has(callee.name));
1536
+ }
1537
+ return false;
1538
+ }
1489
1539
  function isDisallowedArrayType(type) {
1490
1540
  if (!type || !checker) return false;
1491
1541
  if (type.isUnionOrIntersection()) {
1492
1542
  return type.types.some((entry) => isDisallowedArrayType(entry));
1493
1543
  }
1494
- return checker.isArrayType(type) || checker.isTupleType(type);
1544
+ if (checker.isArrayType(type) || checker.isTupleType(type)) return true;
1545
+ return isArrayLikeTypeText(checker.typeToString(type));
1495
1546
  }
1496
1547
  function expressionHasArrayType(expression) {
1497
1548
  if (!hasTypeInformation || !checker || !parserServices?.esTreeNodeToTSNodeMap) return false;
@@ -1500,6 +1551,46 @@ var rule14 = {
1500
1551
  return isDisallowedArrayType(checker.getTypeAtLocation(tsNode));
1501
1552
  }
1502
1553
  return {
1554
+ TSTypeAliasDeclaration(node) {
1555
+ const declaration = node;
1556
+ if (!declaration.id || declaration.id.type !== "Identifier" || !declaration.id.name) return;
1557
+ if (!declaration.typeAnnotation) return;
1558
+ localTypeAliases.set(declaration.id.name, declaration.typeAnnotation);
1559
+ },
1560
+ VariableDeclarator(node) {
1561
+ const declaration = node;
1562
+ if (!declaration.id || declaration.id.type !== "Identifier") return;
1563
+ const id = declaration.id;
1564
+ const variableName = id.name;
1565
+ if (!variableName) return;
1566
+ if (isArrayLikeTypeNode(id.typeAnnotation?.typeAnnotation, /* @__PURE__ */ new Set())) {
1567
+ arrayTypedIdentifiers.add(variableName);
1568
+ }
1569
+ if (declaration.init?.type === "ArrayExpression") {
1570
+ arrayTypedIdentifiers.add(variableName);
1571
+ }
1572
+ if (declaration.init && (declaration.init.type === "ArrowFunctionExpression" || declaration.init.type === "FunctionExpression")) {
1573
+ const functionExpression = declaration.init;
1574
+ if (isArrayLikeTypeNode(functionExpression.returnType?.typeAnnotation, /* @__PURE__ */ new Set())) {
1575
+ arrayReturningFunctions.add(variableName);
1576
+ }
1577
+ if (functionExpression.body?.type === "ArrayExpression") {
1578
+ arrayReturningFunctions.add(variableName);
1579
+ }
1580
+ }
1581
+ },
1582
+ FunctionDeclaration(node) {
1583
+ const declaration = node;
1584
+ if (!declaration.id || declaration.id.type !== "Identifier" || !declaration.id.name) return;
1585
+ const functionName = declaration.id.name;
1586
+ if (isArrayLikeTypeNode(declaration.returnType?.typeAnnotation, /* @__PURE__ */ new Set())) {
1587
+ arrayReturningFunctions.add(functionName);
1588
+ }
1589
+ const firstStatement = declaration.body?.body?.[0];
1590
+ if (firstStatement?.type === "ReturnStatement" && firstStatement.argument?.type === "ArrayExpression") {
1591
+ arrayReturningFunctions.add(functionName);
1592
+ }
1593
+ },
1503
1594
  JSXAttribute(node) {
1504
1595
  const attr = node;
1505
1596
  if (attr.name?.type !== "JSXIdentifier" || !attr.name.name) return;
@@ -1508,7 +1599,8 @@ var rule14 = {
1508
1599
  if (!expression) return;
1509
1600
  const isInlineArray = expression.type === "ArrayExpression";
1510
1601
  const isArrayTyped = expressionHasArrayType(expression);
1511
- if (!isInlineArray && !isArrayTyped) return;
1602
+ const isArrayShapeByAst = expressionHasArrayShapeByAst(expression);
1603
+ if (!isInlineArray && !isArrayTyped && !isArrayShapeByAst) return;
1512
1604
  context.report({
1513
1605
  node: attr.value,
1514
1606
  messageId: "noArrayProps",
package/dist/index.js CHANGED
@@ -1433,6 +1433,13 @@ var rule13 = {
1433
1433
  var no_object_props_default = rule13;
1434
1434
 
1435
1435
  // src/rules/no-array-props.ts
1436
+ function getTypeName(node) {
1437
+ if (!node) return null;
1438
+ const typedNode = node;
1439
+ if (typedNode.type === "Identifier" && typedNode.name) return typedNode.name;
1440
+ if (typedNode.type === "TSQualifiedName" && typedNode.right?.name) return typedNode.right.name;
1441
+ return null;
1442
+ }
1436
1443
  var rule14 = {
1437
1444
  meta: {
1438
1445
  type: "suggestion",
@@ -1449,12 +1456,56 @@ var rule14 = {
1449
1456
  const parserServices = context.sourceCode.parserServices ?? context.parserServices;
1450
1457
  const checker = parserServices?.program?.getTypeChecker();
1451
1458
  const hasTypeInformation = Boolean(checker && parserServices?.esTreeNodeToTSNodeMap);
1459
+ const arrayTypedIdentifiers = /* @__PURE__ */ new Set();
1460
+ const arrayReturningFunctions = /* @__PURE__ */ new Set();
1461
+ const localTypeAliases = /* @__PURE__ */ new Map();
1462
+ function isArrayLikeTypeText(typeText) {
1463
+ return typeText.endsWith("[]") || typeText.startsWith("readonly ") || typeText.startsWith("Array<") || typeText.startsWith("ReadonlyArray<") || typeText.startsWith("[") || typeText.startsWith("readonly [");
1464
+ }
1465
+ function isArrayLikeTypeNode(typeNode, seenAliases) {
1466
+ if (!typeNode) return false;
1467
+ const typedNode = typeNode;
1468
+ if (typedNode.type === "TSArrayType" || typedNode.type === "TSTupleType") return true;
1469
+ if (typedNode.type === "TSParenthesizedType" || typedNode.type === "TSOptionalType") {
1470
+ return isArrayLikeTypeNode(typedNode.typeAnnotation, seenAliases);
1471
+ }
1472
+ if (typedNode.type === "TSTypeOperator") {
1473
+ return isArrayLikeTypeNode(typedNode.typeAnnotation, seenAliases);
1474
+ }
1475
+ if (typedNode.type === "TSUnionType" || typedNode.type === "TSIntersectionType") {
1476
+ return (typedNode.types ?? []).some((entry) => isArrayLikeTypeNode(entry, seenAliases));
1477
+ }
1478
+ if (typedNode.type === "TSTypeReference") {
1479
+ const typeName = getTypeName(typedNode.typeName);
1480
+ if (!typeName) return false;
1481
+ if (typeName === "Array" || typeName === "ReadonlyArray") return true;
1482
+ if (seenAliases.has(typeName)) return false;
1483
+ const aliasType = localTypeAliases.get(typeName);
1484
+ if (!aliasType) return false;
1485
+ const nextSeenAliases = new Set(seenAliases);
1486
+ nextSeenAliases.add(typeName);
1487
+ return isArrayLikeTypeNode(aliasType, nextSeenAliases);
1488
+ }
1489
+ return false;
1490
+ }
1491
+ function expressionHasArrayShapeByAst(expression) {
1492
+ const typedExpression = expression;
1493
+ if (typedExpression.type === "Identifier" && typedExpression.name) {
1494
+ return arrayTypedIdentifiers.has(typedExpression.name);
1495
+ }
1496
+ if (typedExpression.type === "CallExpression" && typedExpression.callee) {
1497
+ const callee = typedExpression.callee;
1498
+ return callee.type === "Identifier" && Boolean(callee.name && arrayReturningFunctions.has(callee.name));
1499
+ }
1500
+ return false;
1501
+ }
1452
1502
  function isDisallowedArrayType(type) {
1453
1503
  if (!type || !checker) return false;
1454
1504
  if (type.isUnionOrIntersection()) {
1455
1505
  return type.types.some((entry) => isDisallowedArrayType(entry));
1456
1506
  }
1457
- return checker.isArrayType(type) || checker.isTupleType(type);
1507
+ if (checker.isArrayType(type) || checker.isTupleType(type)) return true;
1508
+ return isArrayLikeTypeText(checker.typeToString(type));
1458
1509
  }
1459
1510
  function expressionHasArrayType(expression) {
1460
1511
  if (!hasTypeInformation || !checker || !parserServices?.esTreeNodeToTSNodeMap) return false;
@@ -1463,6 +1514,46 @@ var rule14 = {
1463
1514
  return isDisallowedArrayType(checker.getTypeAtLocation(tsNode));
1464
1515
  }
1465
1516
  return {
1517
+ TSTypeAliasDeclaration(node) {
1518
+ const declaration = node;
1519
+ if (!declaration.id || declaration.id.type !== "Identifier" || !declaration.id.name) return;
1520
+ if (!declaration.typeAnnotation) return;
1521
+ localTypeAliases.set(declaration.id.name, declaration.typeAnnotation);
1522
+ },
1523
+ VariableDeclarator(node) {
1524
+ const declaration = node;
1525
+ if (!declaration.id || declaration.id.type !== "Identifier") return;
1526
+ const id = declaration.id;
1527
+ const variableName = id.name;
1528
+ if (!variableName) return;
1529
+ if (isArrayLikeTypeNode(id.typeAnnotation?.typeAnnotation, /* @__PURE__ */ new Set())) {
1530
+ arrayTypedIdentifiers.add(variableName);
1531
+ }
1532
+ if (declaration.init?.type === "ArrayExpression") {
1533
+ arrayTypedIdentifiers.add(variableName);
1534
+ }
1535
+ if (declaration.init && (declaration.init.type === "ArrowFunctionExpression" || declaration.init.type === "FunctionExpression")) {
1536
+ const functionExpression = declaration.init;
1537
+ if (isArrayLikeTypeNode(functionExpression.returnType?.typeAnnotation, /* @__PURE__ */ new Set())) {
1538
+ arrayReturningFunctions.add(variableName);
1539
+ }
1540
+ if (functionExpression.body?.type === "ArrayExpression") {
1541
+ arrayReturningFunctions.add(variableName);
1542
+ }
1543
+ }
1544
+ },
1545
+ FunctionDeclaration(node) {
1546
+ const declaration = node;
1547
+ if (!declaration.id || declaration.id.type !== "Identifier" || !declaration.id.name) return;
1548
+ const functionName = declaration.id.name;
1549
+ if (isArrayLikeTypeNode(declaration.returnType?.typeAnnotation, /* @__PURE__ */ new Set())) {
1550
+ arrayReturningFunctions.add(functionName);
1551
+ }
1552
+ const firstStatement = declaration.body?.body?.[0];
1553
+ if (firstStatement?.type === "ReturnStatement" && firstStatement.argument?.type === "ArrayExpression") {
1554
+ arrayReturningFunctions.add(functionName);
1555
+ }
1556
+ },
1466
1557
  JSXAttribute(node) {
1467
1558
  const attr = node;
1468
1559
  if (attr.name?.type !== "JSXIdentifier" || !attr.name.name) return;
@@ -1471,7 +1562,8 @@ var rule14 = {
1471
1562
  if (!expression) return;
1472
1563
  const isInlineArray = expression.type === "ArrayExpression";
1473
1564
  const isArrayTyped = expressionHasArrayType(expression);
1474
- if (!isInlineArray && !isArrayTyped) return;
1565
+ const isArrayShapeByAst = expressionHasArrayShapeByAst(expression);
1566
+ if (!isInlineArray && !isArrayTyped && !isArrayShapeByAst) return;
1475
1567
  context.report({
1476
1568
  node: attr.value,
1477
1569
  messageId: "noArrayProps",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-sweepit",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "description": "Opinionated architectural lint rules for Sweepit.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -41,5 +41,5 @@
41
41
  "typescript": "^5.9.2",
42
42
  "vitest": "^2.1.3"
43
43
  },
44
- "gitHead": "4a0400e88020f7a562a8cae4830fc80c036f92a1"
44
+ "gitHead": "dd608ba9ac91b2eef9f7319d707b44ee352036cc"
45
45
  }