@fairfox/polly 0.3.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -727,10 +727,12 @@ import { Project, SyntaxKind, Node } from "ts-morph";
727
727
 
728
728
  class HandlerExtractor {
729
729
  project;
730
+ typeGuardCache;
730
731
  constructor(tsConfigPath) {
731
732
  this.project = new Project({
732
733
  tsConfigFilePath: tsConfigPath
733
734
  });
735
+ this.typeGuardCache = new WeakMap;
734
736
  }
735
737
  extractHandlers() {
736
738
  const handlers = [];
@@ -773,6 +775,10 @@ class HandlerExtractor {
773
775
  const mapHandlers = this.extractHandlerMapPattern(node, context, filePath);
774
776
  handlers.push(...mapHandlers);
775
777
  }
778
+ if (Node.isIfStatement(node)) {
779
+ const typeGuardHandlers = this.extractTypeGuardHandlers(node, context, filePath);
780
+ handlers.push(...typeGuardHandlers);
781
+ }
776
782
  });
777
783
  return handlers;
778
784
  }
@@ -983,6 +989,113 @@ class HandlerExtractor {
983
989
  } catch (error) {}
984
990
  return handlers;
985
991
  }
992
+ extractTypeGuardHandlers(ifNode, context, filePath) {
993
+ const handlers = [];
994
+ try {
995
+ const sourceFile = ifNode.getSourceFile();
996
+ let typeGuards = this.typeGuardCache.get(sourceFile);
997
+ if (!typeGuards) {
998
+ typeGuards = this.findTypePredicateFunctions(sourceFile);
999
+ this.typeGuardCache.set(sourceFile, typeGuards);
1000
+ }
1001
+ if (typeGuards.size === 0) {
1002
+ return handlers;
1003
+ }
1004
+ let currentIf = ifNode;
1005
+ while (currentIf) {
1006
+ const handler = this.extractHandlerFromIfClause(currentIf, typeGuards, context, filePath);
1007
+ if (handler) {
1008
+ handlers.push(handler);
1009
+ }
1010
+ const elseStatement = currentIf.getElseStatement();
1011
+ if (elseStatement && Node.isIfStatement(elseStatement)) {
1012
+ currentIf = elseStatement;
1013
+ } else {
1014
+ break;
1015
+ }
1016
+ }
1017
+ } catch (error) {}
1018
+ return handlers;
1019
+ }
1020
+ extractHandlerFromIfClause(ifNode, typeGuards, context, filePath) {
1021
+ try {
1022
+ const condition = ifNode.getExpression();
1023
+ if (!Node.isCallExpression(condition)) {
1024
+ return null;
1025
+ }
1026
+ const funcExpr = condition.getExpression();
1027
+ let funcName;
1028
+ if (Node.isIdentifier(funcExpr)) {
1029
+ funcName = funcExpr.getText();
1030
+ }
1031
+ if (!funcName || !typeGuards.has(funcName)) {
1032
+ return null;
1033
+ }
1034
+ const messageType = typeGuards.get(funcName);
1035
+ const line = ifNode.getStartLineNumber();
1036
+ return {
1037
+ messageType,
1038
+ node: context,
1039
+ assignments: [],
1040
+ preconditions: [],
1041
+ postconditions: [],
1042
+ location: { file: filePath, line }
1043
+ };
1044
+ } catch (error) {
1045
+ return null;
1046
+ }
1047
+ }
1048
+ findTypePredicateFunctions(sourceFile) {
1049
+ const typeGuards = new Map;
1050
+ sourceFile.forEachDescendant((node) => {
1051
+ if (Node.isFunctionDeclaration(node) || Node.isFunctionExpression(node) || Node.isArrowFunction(node)) {
1052
+ const returnType = node.getReturnType();
1053
+ const returnTypeText = returnType.getText();
1054
+ if (/is\s+\w+/.test(returnTypeText)) {
1055
+ let functionName;
1056
+ if (Node.isFunctionDeclaration(node)) {
1057
+ functionName = node.getName();
1058
+ } else if (Node.isFunctionExpression(node)) {
1059
+ const parent = node.getParent();
1060
+ if (Node.isVariableDeclaration(parent)) {
1061
+ functionName = parent.getName();
1062
+ }
1063
+ } else if (Node.isArrowFunction(node)) {
1064
+ const parent = node.getParent();
1065
+ if (Node.isVariableDeclaration(parent)) {
1066
+ functionName = parent.getName();
1067
+ }
1068
+ }
1069
+ if (functionName) {
1070
+ let messageType = null;
1071
+ const typeMatch = returnTypeText.match(/is\s+(\w+)/);
1072
+ if (typeMatch) {
1073
+ const typeName = typeMatch[1];
1074
+ messageType = this.extractMessageTypeFromTypeName(typeName);
1075
+ }
1076
+ if (!messageType) {
1077
+ const body = node.getBody();
1078
+ if (body) {
1079
+ const bodyText = body.getText();
1080
+ const typeValueMatch = bodyText.match(/\.type\s*===?\s*['"](\w+)['"]/);
1081
+ if (typeValueMatch) {
1082
+ messageType = typeValueMatch[1];
1083
+ }
1084
+ }
1085
+ }
1086
+ if (messageType) {
1087
+ typeGuards.set(functionName, messageType);
1088
+ }
1089
+ }
1090
+ }
1091
+ }
1092
+ });
1093
+ return typeGuards;
1094
+ }
1095
+ extractMessageTypeFromTypeName(typeName) {
1096
+ const messageType = typeName.replace(/Message$/, "").replace(/Event$/, "").replace(/Request$/, "").replace(/Command$/, "").replace(/Query$/, "").toLowerCase();
1097
+ return messageType;
1098
+ }
986
1099
  inferContext(filePath) {
987
1100
  const path = filePath.toLowerCase();
988
1101
  if (path.includes("/background/") || path.includes("\\background\\")) {
@@ -2175,4 +2288,4 @@ Stack trace:`, COLORS.gray));
2175
2288
  process.exit(1);
2176
2289
  });
2177
2290
 
2178
- //# debugId=8C53367A419D15AA64756E2164756E21
2291
+ //# debugId=5E943FE5FB56B58764756E2164756E21