@fairfox/polly 0.3.0 → 0.3.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.
|
@@ -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,145 @@ 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
|
+
let messageType = undefined;
|
|
1032
|
+
if (funcName && typeGuards.has(funcName)) {
|
|
1033
|
+
messageType = typeGuards.get(funcName);
|
|
1034
|
+
} else if (Node.isIdentifier(funcExpr)) {
|
|
1035
|
+
messageType = this.resolveImportedTypeGuard(funcExpr);
|
|
1036
|
+
}
|
|
1037
|
+
if (!messageType) {
|
|
1038
|
+
return null;
|
|
1039
|
+
}
|
|
1040
|
+
const line = ifNode.getStartLineNumber();
|
|
1041
|
+
return {
|
|
1042
|
+
messageType,
|
|
1043
|
+
node: context,
|
|
1044
|
+
assignments: [],
|
|
1045
|
+
preconditions: [],
|
|
1046
|
+
postconditions: [],
|
|
1047
|
+
location: { file: filePath, line }
|
|
1048
|
+
};
|
|
1049
|
+
} catch (error) {
|
|
1050
|
+
return null;
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
findTypePredicateFunctions(sourceFile) {
|
|
1054
|
+
const typeGuards = new Map;
|
|
1055
|
+
sourceFile.forEachDescendant((node) => {
|
|
1056
|
+
if (Node.isFunctionDeclaration(node) || Node.isFunctionExpression(node) || Node.isArrowFunction(node)) {
|
|
1057
|
+
const returnType = node.getReturnType();
|
|
1058
|
+
const returnTypeText = returnType.getText();
|
|
1059
|
+
if (/is\s+\w+/.test(returnTypeText)) {
|
|
1060
|
+
let functionName;
|
|
1061
|
+
if (Node.isFunctionDeclaration(node)) {
|
|
1062
|
+
functionName = node.getName();
|
|
1063
|
+
} else if (Node.isFunctionExpression(node)) {
|
|
1064
|
+
const parent = node.getParent();
|
|
1065
|
+
if (Node.isVariableDeclaration(parent)) {
|
|
1066
|
+
functionName = parent.getName();
|
|
1067
|
+
}
|
|
1068
|
+
} else if (Node.isArrowFunction(node)) {
|
|
1069
|
+
const parent = node.getParent();
|
|
1070
|
+
if (Node.isVariableDeclaration(parent)) {
|
|
1071
|
+
functionName = parent.getName();
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
if (functionName) {
|
|
1075
|
+
let messageType = null;
|
|
1076
|
+
const typeMatch = returnTypeText.match(/is\s+(\w+)/);
|
|
1077
|
+
if (typeMatch) {
|
|
1078
|
+
const typeName = typeMatch[1];
|
|
1079
|
+
messageType = this.extractMessageTypeFromTypeName(typeName);
|
|
1080
|
+
}
|
|
1081
|
+
if (!messageType) {
|
|
1082
|
+
const body = node.getBody();
|
|
1083
|
+
if (body) {
|
|
1084
|
+
const bodyText = body.getText();
|
|
1085
|
+
const typeValueMatch = bodyText.match(/\.type\s*===?\s*['"](\w+)['"]/);
|
|
1086
|
+
if (typeValueMatch) {
|
|
1087
|
+
messageType = typeValueMatch[1];
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
if (messageType) {
|
|
1092
|
+
typeGuards.set(functionName, messageType);
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
});
|
|
1098
|
+
return typeGuards;
|
|
1099
|
+
}
|
|
1100
|
+
resolveImportedTypeGuard(identifier) {
|
|
1101
|
+
try {
|
|
1102
|
+
const definitions = identifier.getDefinitionNodes();
|
|
1103
|
+
for (const def of definitions) {
|
|
1104
|
+
if (Node.isFunctionDeclaration(def) || Node.isFunctionExpression(def) || Node.isArrowFunction(def)) {
|
|
1105
|
+
const returnType = def.getReturnType();
|
|
1106
|
+
const returnTypeText = returnType.getText();
|
|
1107
|
+
if (/is\s+\w+/.test(returnTypeText)) {
|
|
1108
|
+
const typeMatch = returnTypeText.match(/is\s+(\w+)/);
|
|
1109
|
+
if (typeMatch) {
|
|
1110
|
+
const typeName = typeMatch[1];
|
|
1111
|
+
return this.extractMessageTypeFromTypeName(typeName);
|
|
1112
|
+
}
|
|
1113
|
+
const body = def.getBody();
|
|
1114
|
+
if (body) {
|
|
1115
|
+
const bodyText = body.getText();
|
|
1116
|
+
const typeValueMatch = bodyText.match(/\.type\s*===?\s*['"](\w+)['"]/);
|
|
1117
|
+
if (typeValueMatch) {
|
|
1118
|
+
return typeValueMatch[1];
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
} catch (error) {}
|
|
1125
|
+
return null;
|
|
1126
|
+
}
|
|
1127
|
+
extractMessageTypeFromTypeName(typeName) {
|
|
1128
|
+
const messageType = typeName.replace(/Message$/, "").replace(/Event$/, "").replace(/Request$/, "").replace(/Command$/, "").replace(/Query$/, "").toLowerCase();
|
|
1129
|
+
return messageType;
|
|
1130
|
+
}
|
|
986
1131
|
inferContext(filePath) {
|
|
987
1132
|
const path = filePath.toLowerCase();
|
|
988
1133
|
if (path.includes("/background/") || path.includes("\\background\\")) {
|
|
@@ -2175,4 +2320,4 @@ Stack trace:`, COLORS.gray));
|
|
|
2175
2320
|
process.exit(1);
|
|
2176
2321
|
});
|
|
2177
2322
|
|
|
2178
|
-
//# debugId=
|
|
2323
|
+
//# debugId=45501E6F6BA7319064756E2164756E21
|