@fairfox/polly 0.2.1 → 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 = [];
@@ -757,7 +759,7 @@ class HandlerExtractor {
757
759
  const expression = node.getExpression();
758
760
  if (Node.isPropertyAccessExpression(expression)) {
759
761
  const methodName = expression.getName();
760
- if (methodName === "on") {
762
+ if (methodName === "on" || methodName === "addEventListener") {
761
763
  const handler = this.extractHandler(node, context, filePath);
762
764
  if (handler) {
763
765
  handlers.push(handler);
@@ -765,6 +767,18 @@ class HandlerExtractor {
765
767
  }
766
768
  }
767
769
  }
770
+ if (Node.isSwitchStatement(node)) {
771
+ const switchHandlers = this.extractSwitchCaseHandlers(node, context, filePath);
772
+ handlers.push(...switchHandlers);
773
+ }
774
+ if (Node.isVariableDeclaration(node)) {
775
+ const mapHandlers = this.extractHandlerMapPattern(node, context, filePath);
776
+ handlers.push(...mapHandlers);
777
+ }
778
+ if (Node.isIfStatement(node)) {
779
+ const typeGuardHandlers = this.extractTypeGuardHandlers(node, context, filePath);
780
+ handlers.push(...typeGuardHandlers);
781
+ }
768
782
  });
769
783
  return handlers;
770
784
  }
@@ -906,6 +920,182 @@ class HandlerExtractor {
906
920
  }
907
921
  return;
908
922
  }
923
+ extractSwitchCaseHandlers(switchNode, context, filePath) {
924
+ const handlers = [];
925
+ try {
926
+ const expression = switchNode.getExpression();
927
+ const expressionText = expression.getText();
928
+ if (!/\.(type|kind|event|action)/.test(expressionText)) {
929
+ return handlers;
930
+ }
931
+ const caseClauses = switchNode.getClauses();
932
+ for (const clause of caseClauses) {
933
+ if (Node.isCaseClause(clause)) {
934
+ const caseExpr = clause.getExpression();
935
+ let messageType = null;
936
+ if (Node.isStringLiteral(caseExpr)) {
937
+ messageType = caseExpr.getLiteralValue();
938
+ }
939
+ if (messageType) {
940
+ const line = clause.getStartLineNumber();
941
+ handlers.push({
942
+ messageType,
943
+ node: context,
944
+ assignments: [],
945
+ preconditions: [],
946
+ postconditions: [],
947
+ location: { file: filePath, line }
948
+ });
949
+ }
950
+ }
951
+ }
952
+ } catch (error) {}
953
+ return handlers;
954
+ }
955
+ extractHandlerMapPattern(varDecl, context, filePath) {
956
+ const handlers = [];
957
+ try {
958
+ const initializer = varDecl.getInitializer();
959
+ if (!initializer || !Node.isObjectLiteralExpression(initializer)) {
960
+ return handlers;
961
+ }
962
+ const varName = varDecl.getName().toLowerCase();
963
+ if (!/(handler|listener|callback|event)s?/.test(varName)) {
964
+ return handlers;
965
+ }
966
+ const properties = initializer.getProperties();
967
+ for (const prop of properties) {
968
+ if (Node.isPropertyAssignment(prop)) {
969
+ const nameNode = prop.getNameNode();
970
+ let messageType = null;
971
+ if (Node.isStringLiteral(nameNode)) {
972
+ messageType = nameNode.getLiteralValue();
973
+ } else if (Node.isIdentifier(nameNode)) {
974
+ messageType = nameNode.getText();
975
+ }
976
+ if (messageType) {
977
+ const line = prop.getStartLineNumber();
978
+ handlers.push({
979
+ messageType,
980
+ node: context,
981
+ assignments: [],
982
+ preconditions: [],
983
+ postconditions: [],
984
+ location: { file: filePath, line }
985
+ });
986
+ }
987
+ }
988
+ }
989
+ } catch (error) {}
990
+ return handlers;
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
+ }
909
1099
  inferContext(filePath) {
910
1100
  const path = filePath.toLowerCase();
911
1101
  if (path.includes("/background/") || path.includes("\\background\\")) {
@@ -926,6 +1116,15 @@ class HandlerExtractor {
926
1116
  if (path.includes("/offscreen/") || path.includes("\\offscreen\\")) {
927
1117
  return "offscreen";
928
1118
  }
1119
+ if (path.includes("/server/") || path.includes("\\server\\") || path.includes("/server.")) {
1120
+ return "server";
1121
+ }
1122
+ if (path.includes("/client/") || path.includes("\\client\\") || path.includes("/client.")) {
1123
+ return "client";
1124
+ }
1125
+ if (path.includes("/worker/") || path.includes("\\worker\\") || path.includes("service-worker")) {
1126
+ return "worker";
1127
+ }
929
1128
  return "unknown";
930
1129
  }
931
1130
  }
@@ -2089,4 +2288,4 @@ Stack trace:`, COLORS.gray));
2089
2288
  process.exit(1);
2090
2289
  });
2091
2290
 
2092
- //# debugId=F6E692DF29A2A67064756E2164756E21
2291
+ //# debugId=5E943FE5FB56B58764756E2164756E21