@fairfox/polly 0.5.2 → 0.6.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/cli/polly.js +9 -9
- package/dist/cli/polly.js.map +4 -4
- package/dist/cli/template-utils.js +3 -3
- package/dist/cli/template-utils.js.map +3 -3
- package/dist/src/shared/state/app-state.d.ts +8 -0
- package/dist/vendor/verify/src/cli.js +78 -71
- package/dist/vendor/verify/src/cli.js.map +10 -10
- package/dist/vendor/verify/src/public-api.d.ts +41 -0
- package/dist/vendor/verify/src/public-api.js +26 -0
- package/dist/vendor/verify/src/public-api.js.map +10 -0
- package/dist/vendor/visualize/src/cli.js +108 -104
- package/dist/vendor/visualize/src/cli.js.map +13 -13
- package/package.json +15 -2
- package/templates/pwa/build.ts.template +37 -37
- package/templates/pwa/server.ts.template +53 -53
- package/templates/pwa/src/service-worker.ts.template +131 -135
- package/templates/pwa/src/shared-worker.ts.template +114 -109
- package/dist/shared/state/app-state.d.ts +0 -8
- /package/dist/{background → src/background}/api-client.d.ts +0 -0
- /package/dist/{background → src/background}/context-menu.d.ts +0 -0
- /package/dist/{background → src/background}/index.d.ts +0 -0
- /package/dist/{background → src/background}/log-store.d.ts +0 -0
- /package/dist/{background → src/background}/message-router.d.ts +0 -0
- /package/dist/{background → src/background}/offscreen-manager.d.ts +0 -0
- /package/dist/{index.d.ts → src/index.d.ts} +0 -0
- /package/dist/{shared → src/shared}/adapters/chrome/context-menus.chrome.d.ts +0 -0
- /package/dist/{shared → src/shared}/adapters/chrome/offscreen.chrome.d.ts +0 -0
- /package/dist/{shared → src/shared}/adapters/chrome/runtime.chrome.d.ts +0 -0
- /package/dist/{shared → src/shared}/adapters/chrome/storage.chrome.d.ts +0 -0
- /package/dist/{shared → src/shared}/adapters/chrome/tabs.chrome.d.ts +0 -0
- /package/dist/{shared → src/shared}/adapters/chrome/window.chrome.d.ts +0 -0
- /package/dist/{shared → src/shared}/adapters/context-menus.adapter.d.ts +0 -0
- /package/dist/{shared → src/shared}/adapters/fetch.adapter.d.ts +0 -0
- /package/dist/{shared → src/shared}/adapters/index.d.ts +0 -0
- /package/dist/{shared → src/shared}/adapters/logger.adapter.d.ts +0 -0
- /package/dist/{shared → src/shared}/adapters/offscreen.adapter.d.ts +0 -0
- /package/dist/{shared → src/shared}/adapters/runtime.adapter.d.ts +0 -0
- /package/dist/{shared → src/shared}/adapters/storage.adapter.d.ts +0 -0
- /package/dist/{shared → src/shared}/adapters/tabs.adapter.d.ts +0 -0
- /package/dist/{shared → src/shared}/adapters/window.adapter.d.ts +0 -0
- /package/dist/{shared → src/shared}/lib/context-helpers.d.ts +0 -0
- /package/dist/{shared → src/shared}/lib/context-specific-helpers.d.ts +0 -0
- /package/dist/{shared → src/shared}/lib/errors.d.ts +0 -0
- /package/dist/{shared → src/shared}/lib/handler-execution-tracker.d.ts +0 -0
- /package/dist/{shared → src/shared}/lib/message-bus.d.ts +0 -0
- /package/dist/{shared → src/shared}/lib/state.d.ts +0 -0
- /package/dist/{shared → src/shared}/lib/test-helpers.d.ts +0 -0
- /package/dist/{shared → src/shared}/types/messages.d.ts +0 -0
|
@@ -27,7 +27,7 @@ class TLAGenerator {
|
|
|
27
27
|
this.lines = [];
|
|
28
28
|
this.indent = 0;
|
|
29
29
|
const spec = this.generateSpec(config, analysis);
|
|
30
|
-
const cfg = this.generateConfig(config
|
|
30
|
+
const cfg = this.generateConfig(config);
|
|
31
31
|
return { spec, cfg };
|
|
32
32
|
}
|
|
33
33
|
generateSpec(config, analysis) {
|
|
@@ -35,7 +35,7 @@ class TLAGenerator {
|
|
|
35
35
|
this.indent = 0;
|
|
36
36
|
this.addHeader();
|
|
37
37
|
this.addExtends();
|
|
38
|
-
this.addConstants(config
|
|
38
|
+
this.addConstants(config);
|
|
39
39
|
this.addMessageTypes(config, analysis);
|
|
40
40
|
this.addStateType(config, analysis);
|
|
41
41
|
this.addVariables();
|
|
@@ -48,7 +48,7 @@ class TLAGenerator {
|
|
|
48
48
|
return this.lines.join(`
|
|
49
49
|
`);
|
|
50
50
|
}
|
|
51
|
-
generateConfig(config
|
|
51
|
+
generateConfig(config) {
|
|
52
52
|
const lines = [];
|
|
53
53
|
lines.push("SPECIFICATION UserSpec");
|
|
54
54
|
lines.push("");
|
|
@@ -107,8 +107,8 @@ class TLAGenerator {
|
|
|
107
107
|
this.line("EXTENDS MessageRouter");
|
|
108
108
|
this.line("");
|
|
109
109
|
}
|
|
110
|
-
addConstants(config
|
|
111
|
-
const hasCustomConstants = Object.entries(config.state).some(([
|
|
110
|
+
addConstants(config) {
|
|
111
|
+
const hasCustomConstants = Object.entries(config.state).some(([_, fieldConfig]) => {
|
|
112
112
|
if (typeof fieldConfig !== "object" || fieldConfig === null)
|
|
113
113
|
return false;
|
|
114
114
|
return "maxLength" in fieldConfig && fieldConfig.maxLength !== null || "max" in fieldConfig && fieldConfig.max !== null || "maxSize" in fieldConfig && fieldConfig.maxSize !== null;
|
|
@@ -140,7 +140,7 @@ class TLAGenerator {
|
|
|
140
140
|
this.indent--;
|
|
141
141
|
this.line("");
|
|
142
142
|
}
|
|
143
|
-
addStateType(config,
|
|
143
|
+
addStateType(config, _analysis) {
|
|
144
144
|
this.line("\\* Generic value type for sequences and maps");
|
|
145
145
|
this.line("\\* Bounded to allow model checking");
|
|
146
146
|
this.line('Value == {"v1", "v2", "v3"}');
|
|
@@ -169,7 +169,7 @@ class TLAGenerator {
|
|
|
169
169
|
this.line("]");
|
|
170
170
|
this.line("");
|
|
171
171
|
}
|
|
172
|
-
addMessageTypes(
|
|
172
|
+
addMessageTypes(_config, analysis) {
|
|
173
173
|
if (analysis.messageTypes.length === 0) {
|
|
174
174
|
return;
|
|
175
175
|
}
|
|
@@ -186,7 +186,7 @@ class TLAGenerator {
|
|
|
186
186
|
this.line("allVars == <<ports, messages, pendingRequests, delivered, routingDepth, time, contextStates>>");
|
|
187
187
|
this.line("");
|
|
188
188
|
}
|
|
189
|
-
addInit(config,
|
|
189
|
+
addInit(config, _analysis) {
|
|
190
190
|
this.line("\\* Initial application state");
|
|
191
191
|
this.line("InitialState == [");
|
|
192
192
|
this.indent++;
|
|
@@ -247,6 +247,8 @@ class TLAGenerator {
|
|
|
247
247
|
const messageTypes = Array.from(handlersByType.keys());
|
|
248
248
|
for (let i = 0;i < messageTypes.length; i++) {
|
|
249
249
|
const msgType = messageTypes[i];
|
|
250
|
+
if (!msgType)
|
|
251
|
+
continue;
|
|
250
252
|
const actionName = this.messageTypeToActionName(msgType);
|
|
251
253
|
if (i === 0) {
|
|
252
254
|
this.line(`IF msgType = "${msgType}" THEN ${actionName}(ctx)`);
|
|
@@ -304,6 +306,8 @@ class TLAGenerator {
|
|
|
304
306
|
this.indent++;
|
|
305
307
|
for (let i = 0;i < validAssignments.length; i++) {
|
|
306
308
|
const assignment = validAssignments[i];
|
|
309
|
+
if (!assignment || assignment.value === undefined)
|
|
310
|
+
continue;
|
|
307
311
|
const fieldName = this.sanitizeFieldName(assignment.field);
|
|
308
312
|
const value = this.assignmentValueToTLA(assignment.value);
|
|
309
313
|
const suffix = i < validAssignments.length - 1 ? "," : "";
|
|
@@ -325,10 +329,10 @@ class TLAGenerator {
|
|
|
325
329
|
tsExpressionToTLA(expr, isPrimed = false) {
|
|
326
330
|
let tla = expr;
|
|
327
331
|
const statePrefix = isPrimed ? "contextStates'[ctx]" : "contextStates[ctx]";
|
|
328
|
-
tla = tla.replace(/state\.([a-zA-Z_][a-zA-Z0-9_.]*)/g, (
|
|
332
|
+
tla = tla.replace(/state\.([a-zA-Z_][a-zA-Z0-9_.]*)/g, (_match, path2) => {
|
|
329
333
|
return `${statePrefix}.${this.sanitizeFieldName(path2)}`;
|
|
330
334
|
});
|
|
331
|
-
tla = tla.replace(/payload\.([a-zA-Z_][a-zA-Z0-9_.]*)/g, (
|
|
335
|
+
tla = tla.replace(/payload\.([a-zA-Z_][a-zA-Z0-9_.]*)/g, (_match, path2) => {
|
|
332
336
|
return `payload.${this.sanitizeFieldName(path2)}`;
|
|
333
337
|
});
|
|
334
338
|
tla = tla.replace(/===/g, "=");
|
|
@@ -366,7 +370,7 @@ class TLAGenerator {
|
|
|
366
370
|
}
|
|
367
371
|
return "NULL";
|
|
368
372
|
}
|
|
369
|
-
addRouteWithHandlers(
|
|
373
|
+
addRouteWithHandlers(_config, analysis) {
|
|
370
374
|
this.line("\\* =============================================================================");
|
|
371
375
|
this.line("\\* Message Routing with State Transitions");
|
|
372
376
|
this.line("\\* =============================================================================");
|
|
@@ -401,7 +405,7 @@ class TLAGenerator {
|
|
|
401
405
|
this.indent--;
|
|
402
406
|
this.line("");
|
|
403
407
|
}
|
|
404
|
-
addNext(
|
|
408
|
+
addNext(_config, analysis) {
|
|
405
409
|
this.line("\\* Next state relation (extends MessageRouter)");
|
|
406
410
|
this.line("UserNext ==");
|
|
407
411
|
this.indent++;
|
|
@@ -426,7 +430,7 @@ class TLAGenerator {
|
|
|
426
430
|
this.line("UserSpec == UserInit /\\ [][UserNext]_allVars /\\ WF_allVars(UserNext)");
|
|
427
431
|
this.line("");
|
|
428
432
|
}
|
|
429
|
-
addInvariants(
|
|
433
|
+
addInvariants(_config, _analysis) {
|
|
430
434
|
this.line("\\* =============================================================================");
|
|
431
435
|
this.line("\\* Application Invariants");
|
|
432
436
|
this.line("\\* =============================================================================");
|
|
@@ -450,7 +454,7 @@ class TLAGenerator {
|
|
|
450
454
|
this.line("");
|
|
451
455
|
this.line("=============================================================================");
|
|
452
456
|
}
|
|
453
|
-
fieldConfigToTLAType(
|
|
457
|
+
fieldConfigToTLAType(_fieldPath, fieldConfig, _config) {
|
|
454
458
|
if ("type" in fieldConfig) {
|
|
455
459
|
if (fieldConfig.type === "boolean") {
|
|
456
460
|
return "BOOLEAN";
|
|
@@ -461,11 +465,9 @@ class TLAGenerator {
|
|
|
461
465
|
}
|
|
462
466
|
}
|
|
463
467
|
if ("maxLength" in fieldConfig) {
|
|
464
|
-
const constName = this.fieldToConstName(fieldPath);
|
|
465
468
|
return `Seq(Value)`;
|
|
466
469
|
}
|
|
467
470
|
if ("min" in fieldConfig && "max" in fieldConfig) {
|
|
468
|
-
const constName = this.fieldToConstName(fieldPath);
|
|
469
471
|
const min = fieldConfig.min || 0;
|
|
470
472
|
const max = fieldConfig.max || 100;
|
|
471
473
|
return `${min}..${max}`;
|
|
@@ -538,7 +540,6 @@ import * as fs2 from "node:fs";
|
|
|
538
540
|
import * as path2 from "node:path";
|
|
539
541
|
|
|
540
542
|
class DockerRunner {
|
|
541
|
-
containerName = "web-ext-tla-verify";
|
|
542
543
|
async isDockerAvailable() {
|
|
543
544
|
try {
|
|
544
545
|
const result = await this.runCommand("docker", ["--version"]);
|
|
@@ -609,8 +610,8 @@ class DockerRunner {
|
|
|
609
610
|
return {
|
|
610
611
|
success: true,
|
|
611
612
|
stats: {
|
|
612
|
-
statesGenerated: statesMatch ? Number.parseInt(statesMatch[1]) : 0,
|
|
613
|
-
distinctStates: distinctMatch ? Number.parseInt(distinctMatch[1]) : 0
|
|
613
|
+
statesGenerated: statesMatch?.[1] ? Number.parseInt(statesMatch[1]) : 0,
|
|
614
|
+
distinctStates: distinctMatch?.[1] ? Number.parseInt(distinctMatch[1]) : 0
|
|
614
615
|
},
|
|
615
616
|
output
|
|
616
617
|
};
|
|
@@ -635,7 +636,7 @@ class DockerRunner {
|
|
|
635
636
|
}
|
|
636
637
|
extractError(output) {
|
|
637
638
|
const errorMatch = output.match(/Error: (.*?)(?:\n|$)/);
|
|
638
|
-
if (errorMatch) {
|
|
639
|
+
if (errorMatch?.[1]) {
|
|
639
640
|
return errorMatch[1];
|
|
640
641
|
}
|
|
641
642
|
if (output.includes("Parse Error")) {
|
|
@@ -723,7 +724,7 @@ import * as path3 from "node:path";
|
|
|
723
724
|
import { Project as Project2 } from "ts-morph";
|
|
724
725
|
|
|
725
726
|
// vendor/analysis/src/extract/handlers.ts
|
|
726
|
-
import { Project, SyntaxKind
|
|
727
|
+
import { Project, SyntaxKind, Node as Node2 } from "ts-morph";
|
|
727
728
|
|
|
728
729
|
// vendor/analysis/src/extract/relationships.ts
|
|
729
730
|
import { Node } from "ts-morph";
|
|
@@ -826,7 +827,7 @@ class RelationshipExtractor {
|
|
|
826
827
|
const objectExpr = expr.getExpression();
|
|
827
828
|
const objectName = objectExpr.getText();
|
|
828
829
|
const methodName = expr.getName();
|
|
829
|
-
targetComponent = this.inferComponentFromCall(objectName
|
|
830
|
+
targetComponent = this.inferComponentFromCall(objectName);
|
|
830
831
|
if (!targetComponent) {
|
|
831
832
|
return null;
|
|
832
833
|
}
|
|
@@ -857,7 +858,7 @@ class RelationshipExtractor {
|
|
|
857
858
|
rootObject = rootObject.getExpression();
|
|
858
859
|
}
|
|
859
860
|
const objectName = rootObject.getText();
|
|
860
|
-
const targetComponent = this.inferComponentFromCall(objectName
|
|
861
|
+
const targetComponent = this.inferComponentFromCall(objectName);
|
|
861
862
|
if (!targetComponent) {
|
|
862
863
|
return null;
|
|
863
864
|
}
|
|
@@ -894,7 +895,7 @@ class RelationshipExtractor {
|
|
|
894
895
|
}
|
|
895
896
|
extractFromFetchCall(callExpr, handlerName) {
|
|
896
897
|
const args = callExpr.getArguments();
|
|
897
|
-
if (args.length === 0) {
|
|
898
|
+
if (args.length === 0 || !args[0]) {
|
|
898
899
|
return null;
|
|
899
900
|
}
|
|
900
901
|
const urlArg = args[0].getText();
|
|
@@ -913,7 +914,7 @@ class RelationshipExtractor {
|
|
|
913
914
|
evidence: [`fetch() call to: ${urlArg}`]
|
|
914
915
|
};
|
|
915
916
|
}
|
|
916
|
-
inferComponentFromCall(objectName
|
|
917
|
+
inferComponentFromCall(objectName) {
|
|
917
918
|
const mappings = {
|
|
918
919
|
db: "db_client",
|
|
919
920
|
database: "database",
|
|
@@ -990,7 +991,7 @@ class RelationshipExtractor {
|
|
|
990
991
|
}
|
|
991
992
|
if (modulePath.includes("/service") || modulePath.includes("/services")) {
|
|
992
993
|
const match = modulePath.match(/\/([^/]+)\.ts$/);
|
|
993
|
-
if (match) {
|
|
994
|
+
if (match && match[1]) {
|
|
994
995
|
return this.toComponentId(match[1]);
|
|
995
996
|
}
|
|
996
997
|
}
|
|
@@ -1075,7 +1076,7 @@ class HandlerExtractor {
|
|
|
1075
1076
|
const handlers = [];
|
|
1076
1077
|
const messageTypes = new Set;
|
|
1077
1078
|
const sourceFiles = this.project.getSourceFiles();
|
|
1078
|
-
if (process.env
|
|
1079
|
+
if (process.env["POLLY_DEBUG"]) {
|
|
1079
1080
|
console.log(`[DEBUG] Loaded ${sourceFiles.length} source files`);
|
|
1080
1081
|
if (sourceFiles.length <= 20) {
|
|
1081
1082
|
for (const sf of sourceFiles) {
|
|
@@ -1090,7 +1091,7 @@ class HandlerExtractor {
|
|
|
1090
1091
|
messageTypes.add(handler.messageType);
|
|
1091
1092
|
}
|
|
1092
1093
|
}
|
|
1093
|
-
if (process.env
|
|
1094
|
+
if (process.env["POLLY_DEBUG"]) {
|
|
1094
1095
|
console.log(`[DEBUG] Total handlers extracted: ${handlers.length}`);
|
|
1095
1096
|
}
|
|
1096
1097
|
return {
|
|
@@ -1207,7 +1208,7 @@ class HandlerExtractor {
|
|
|
1207
1208
|
extractVerificationConditions(funcNode, preconditions, postconditions) {
|
|
1208
1209
|
const body = funcNode.getBody();
|
|
1209
1210
|
const statements = Node2.isBlock(body) ? body.getStatements() : [body];
|
|
1210
|
-
statements.forEach((statement
|
|
1211
|
+
statements.forEach((statement) => {
|
|
1211
1212
|
if (Node2.isExpressionStatement(statement)) {
|
|
1212
1213
|
const expr = statement.getExpression();
|
|
1213
1214
|
if (Node2.isCallExpression(expr)) {
|
|
@@ -1271,13 +1272,13 @@ class HandlerExtractor {
|
|
|
1271
1272
|
if (Node2.isNumericLiteral(node)) {
|
|
1272
1273
|
return node.getLiteralValue();
|
|
1273
1274
|
}
|
|
1274
|
-
if (node.getKind() ===
|
|
1275
|
+
if (node.getKind() === SyntaxKind.TrueKeyword) {
|
|
1275
1276
|
return true;
|
|
1276
1277
|
}
|
|
1277
|
-
if (node.getKind() ===
|
|
1278
|
+
if (node.getKind() === SyntaxKind.FalseKeyword) {
|
|
1278
1279
|
return false;
|
|
1279
1280
|
}
|
|
1280
|
-
if (node.getKind() ===
|
|
1281
|
+
if (node.getKind() === SyntaxKind.NullKeyword) {
|
|
1281
1282
|
return null;
|
|
1282
1283
|
}
|
|
1283
1284
|
return;
|
|
@@ -1360,7 +1361,7 @@ class HandlerExtractor {
|
|
|
1360
1361
|
typeGuards = this.findTypePredicateFunctions(sourceFile);
|
|
1361
1362
|
this.typeGuardCache.set(sourceFile, typeGuards);
|
|
1362
1363
|
}
|
|
1363
|
-
if (process.env
|
|
1364
|
+
if (process.env["POLLY_DEBUG"]) {
|
|
1364
1365
|
console.log(`[DEBUG] File: ${sourceFile.getBaseName()}`);
|
|
1365
1366
|
console.log(`[DEBUG] Local type guards found: ${typeGuards.size}`);
|
|
1366
1367
|
if (typeGuards.size > 0) {
|
|
@@ -1374,7 +1375,7 @@ class HandlerExtractor {
|
|
|
1374
1375
|
const handler = this.extractHandlerFromIfClause(currentIf, typeGuards, context, filePath);
|
|
1375
1376
|
if (handler) {
|
|
1376
1377
|
handlers.push(handler);
|
|
1377
|
-
if (process.env
|
|
1378
|
+
if (process.env["POLLY_DEBUG"]) {
|
|
1378
1379
|
console.log(`[DEBUG] Found handler: ${handler.messageType} at line ${handler.location.line}`);
|
|
1379
1380
|
}
|
|
1380
1381
|
}
|
|
@@ -1386,7 +1387,7 @@ class HandlerExtractor {
|
|
|
1386
1387
|
}
|
|
1387
1388
|
}
|
|
1388
1389
|
} catch (error) {
|
|
1389
|
-
if (process.env
|
|
1390
|
+
if (process.env["POLLY_DEBUG"]) {
|
|
1390
1391
|
console.log(`[DEBUG] Error in extractTypeGuardHandlers: ${error}`);
|
|
1391
1392
|
}
|
|
1392
1393
|
}
|
|
@@ -1394,7 +1395,8 @@ class HandlerExtractor {
|
|
|
1394
1395
|
}
|
|
1395
1396
|
extractHandlerFromIfClause(ifNode, typeGuards, context, filePath) {
|
|
1396
1397
|
try {
|
|
1397
|
-
const
|
|
1398
|
+
const ifStmt = ifNode;
|
|
1399
|
+
const condition = ifStmt.getExpression();
|
|
1398
1400
|
if (!Node2.isCallExpression(condition)) {
|
|
1399
1401
|
return null;
|
|
1400
1402
|
}
|
|
@@ -1403,32 +1405,32 @@ class HandlerExtractor {
|
|
|
1403
1405
|
if (Node2.isIdentifier(funcExpr)) {
|
|
1404
1406
|
funcName = funcExpr.getText();
|
|
1405
1407
|
}
|
|
1406
|
-
if (process.env
|
|
1408
|
+
if (process.env["POLLY_DEBUG"] && funcName) {
|
|
1407
1409
|
console.log(`[DEBUG] Processing if condition with function: ${funcName}`);
|
|
1408
1410
|
}
|
|
1409
1411
|
let messageType = undefined;
|
|
1410
1412
|
if (funcName && typeGuards.has(funcName)) {
|
|
1411
1413
|
messageType = typeGuards.get(funcName);
|
|
1412
|
-
if (process.env
|
|
1414
|
+
if (process.env["POLLY_DEBUG"]) {
|
|
1413
1415
|
console.log(`[DEBUG] Found in local type guards: ${funcName} → ${messageType}`);
|
|
1414
1416
|
}
|
|
1415
1417
|
} else if (Node2.isIdentifier(funcExpr)) {
|
|
1416
|
-
if (process.env
|
|
1418
|
+
if (process.env["POLLY_DEBUG"]) {
|
|
1417
1419
|
console.log(`[DEBUG] Not found locally, trying import resolution for: ${funcName}`);
|
|
1418
1420
|
}
|
|
1419
|
-
messageType = this.resolveImportedTypeGuard(funcExpr);
|
|
1421
|
+
messageType = this.resolveImportedTypeGuard(funcExpr) ?? undefined;
|
|
1420
1422
|
}
|
|
1421
1423
|
if (!messageType) {
|
|
1422
|
-
if (process.env
|
|
1424
|
+
if (process.env["POLLY_DEBUG"] && funcName) {
|
|
1423
1425
|
console.log(`[DEBUG] Could not resolve message type for: ${funcName}`);
|
|
1424
1426
|
}
|
|
1425
1427
|
return null;
|
|
1426
1428
|
}
|
|
1427
|
-
const line =
|
|
1428
|
-
const sourceFile =
|
|
1429
|
+
const line = ifStmt.getStartLineNumber();
|
|
1430
|
+
const sourceFile = ifStmt.getSourceFile();
|
|
1429
1431
|
const handlerName = `${messageType}_handler`;
|
|
1430
1432
|
let relationships = undefined;
|
|
1431
|
-
const thenStatement =
|
|
1433
|
+
const thenStatement = ifStmt.getThenStatement();
|
|
1432
1434
|
if (thenStatement) {
|
|
1433
1435
|
const detectedRelationships = this.relationshipExtractor.extractFromHandler(thenStatement, sourceFile, handlerName);
|
|
1434
1436
|
if (detectedRelationships.length > 0) {
|
|
@@ -1481,7 +1483,7 @@ class HandlerExtractor {
|
|
|
1481
1483
|
const bodyText = body.getText();
|
|
1482
1484
|
const typeValueMatch = bodyText.match(/\.type\s*===?\s*['"](\w+)['"]/);
|
|
1483
1485
|
if (typeValueMatch) {
|
|
1484
|
-
messageType = typeValueMatch[1];
|
|
1486
|
+
messageType = typeValueMatch[1] ?? null;
|
|
1485
1487
|
}
|
|
1486
1488
|
}
|
|
1487
1489
|
}
|
|
@@ -1499,7 +1501,7 @@ class HandlerExtractor {
|
|
|
1499
1501
|
const funcName = identifier.getText();
|
|
1500
1502
|
const definitions = identifier.getDefinitionNodes();
|
|
1501
1503
|
if (definitions.length === 0) {
|
|
1502
|
-
if (process.env
|
|
1504
|
+
if (process.env["POLLY_DEBUG"]) {
|
|
1503
1505
|
console.log(`[DEBUG] No definitions found for imported function: ${funcName}`);
|
|
1504
1506
|
}
|
|
1505
1507
|
return null;
|
|
@@ -1507,7 +1509,7 @@ class HandlerExtractor {
|
|
|
1507
1509
|
for (const def of definitions) {
|
|
1508
1510
|
if (Node2.isFunctionDeclaration(def) || Node2.isFunctionExpression(def) || Node2.isArrowFunction(def)) {
|
|
1509
1511
|
const returnTypeNode = def.getReturnTypeNode();
|
|
1510
|
-
if (process.env
|
|
1512
|
+
if (process.env["POLLY_DEBUG"]) {
|
|
1511
1513
|
const returnType = def.getReturnType().getText();
|
|
1512
1514
|
console.log(`[DEBUG] Function ${funcName} return type (resolved): ${returnType}`);
|
|
1513
1515
|
console.log(`[DEBUG] Has return type node: ${!!returnTypeNode}`);
|
|
@@ -1519,7 +1521,7 @@ class HandlerExtractor {
|
|
|
1519
1521
|
const typeName = typeNode.getText();
|
|
1520
1522
|
const messageType = this.extractMessageTypeFromTypeName(typeName);
|
|
1521
1523
|
if (messageType) {
|
|
1522
|
-
if (process.env
|
|
1524
|
+
if (process.env["POLLY_DEBUG"]) {
|
|
1523
1525
|
console.log(`[DEBUG] Resolved ${funcName} → ${messageType} (from AST type predicate)`);
|
|
1524
1526
|
}
|
|
1525
1527
|
return messageType;
|
|
@@ -1531,8 +1533,8 @@ class HandlerExtractor {
|
|
|
1531
1533
|
const bodyText = body.getText();
|
|
1532
1534
|
const typeValueMatch = bodyText.match(/\.type\s*===?\s*['"](\w+)['"]/);
|
|
1533
1535
|
if (typeValueMatch) {
|
|
1534
|
-
const messageType = typeValueMatch[1];
|
|
1535
|
-
if (process.env
|
|
1536
|
+
const messageType = typeValueMatch[1] ?? null;
|
|
1537
|
+
if (process.env["POLLY_DEBUG"]) {
|
|
1536
1538
|
console.log(`[DEBUG] Resolved ${funcName} → ${messageType} (from body)`);
|
|
1537
1539
|
}
|
|
1538
1540
|
return messageType;
|
|
@@ -1541,7 +1543,7 @@ class HandlerExtractor {
|
|
|
1541
1543
|
}
|
|
1542
1544
|
}
|
|
1543
1545
|
} catch (error) {
|
|
1544
|
-
if (process.env
|
|
1546
|
+
if (process.env["POLLY_DEBUG"]) {
|
|
1545
1547
|
console.log(`[DEBUG] Error resolving imported type guard: ${error}`);
|
|
1546
1548
|
}
|
|
1547
1549
|
}
|
|
@@ -1596,7 +1598,7 @@ class TypeExtractor {
|
|
|
1596
1598
|
const stateType = stateFilePath ? this.extractStateType(stateFilePath) : this.findStateType();
|
|
1597
1599
|
const messageTypes = this.findMessageTypes();
|
|
1598
1600
|
const fields = stateType ? this.analyzeFields(stateType) : [];
|
|
1599
|
-
const configFilePath = this.project.getCompilerOptions()
|
|
1601
|
+
const configFilePath = this.project.getCompilerOptions()["configFilePath"];
|
|
1600
1602
|
const tsConfigPath = typeof configFilePath === "string" ? configFilePath : "tsconfig.json";
|
|
1601
1603
|
const handlerExtractor = new HandlerExtractor(tsConfigPath);
|
|
1602
1604
|
const handlerAnalysis = handlerExtractor.extractHandlers();
|
|
@@ -1724,10 +1726,13 @@ class TypeExtractor {
|
|
|
1724
1726
|
}
|
|
1725
1727
|
if (type.isObject()) {
|
|
1726
1728
|
const properties = {};
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
const
|
|
1730
|
-
|
|
1729
|
+
const sourceFile = this.project.getSourceFiles()[0];
|
|
1730
|
+
if (sourceFile) {
|
|
1731
|
+
for (const prop of type.getProperties()) {
|
|
1732
|
+
const propName = prop.getName();
|
|
1733
|
+
const propType = prop.getTypeAtLocation(sourceFile);
|
|
1734
|
+
properties[propName] = this.convertType(propType, propName);
|
|
1735
|
+
}
|
|
1731
1736
|
}
|
|
1732
1737
|
return {
|
|
1733
1738
|
name,
|
|
@@ -1780,7 +1785,7 @@ class TypeExtractor {
|
|
|
1780
1785
|
analysis.confidence = "low";
|
|
1781
1786
|
analysis.suggestions.push("Choose maxLength: 5 (fast), 10 (balanced), or 20 (thorough)");
|
|
1782
1787
|
analysis.bounds.maxLength = undefined;
|
|
1783
|
-
const foundBound = this.findArrayBound(
|
|
1788
|
+
const foundBound = this.findArrayBound();
|
|
1784
1789
|
if (foundBound) {
|
|
1785
1790
|
analysis.confidence = "medium";
|
|
1786
1791
|
analysis.evidence.push(`Found array check: ${foundBound.evidence}`);
|
|
@@ -1793,7 +1798,7 @@ class TypeExtractor {
|
|
|
1793
1798
|
analysis.suggestions.push("Provide min and max values based on your application logic");
|
|
1794
1799
|
analysis.bounds.min = undefined;
|
|
1795
1800
|
analysis.bounds.max = undefined;
|
|
1796
|
-
const foundBound = this.findNumberBound(
|
|
1801
|
+
const foundBound = this.findNumberBound();
|
|
1797
1802
|
if (foundBound) {
|
|
1798
1803
|
analysis.confidence = "high";
|
|
1799
1804
|
analysis.evidence.push(`Found comparison: ${foundBound.evidence}`);
|
|
@@ -1815,10 +1820,10 @@ class TypeExtractor {
|
|
|
1815
1820
|
}
|
|
1816
1821
|
return analysis;
|
|
1817
1822
|
}
|
|
1818
|
-
findArrayBound(
|
|
1823
|
+
findArrayBound() {
|
|
1819
1824
|
return null;
|
|
1820
1825
|
}
|
|
1821
|
-
findNumberBound(
|
|
1826
|
+
findNumberBound() {
|
|
1822
1827
|
return null;
|
|
1823
1828
|
}
|
|
1824
1829
|
}
|
|
@@ -1866,7 +1871,7 @@ class ConfigGenerator {
|
|
|
1866
1871
|
this.line("");
|
|
1867
1872
|
}
|
|
1868
1873
|
addExport() {
|
|
1869
|
-
this.line("export
|
|
1874
|
+
this.line("export const verificationConfig = defineVerification({");
|
|
1870
1875
|
this.indent++;
|
|
1871
1876
|
}
|
|
1872
1877
|
closeExport() {
|
|
@@ -1878,6 +1883,8 @@ class ConfigGenerator {
|
|
|
1878
1883
|
this.indent++;
|
|
1879
1884
|
for (let i = 0;i < fields.length; i++) {
|
|
1880
1885
|
const field = fields[i];
|
|
1886
|
+
if (!field)
|
|
1887
|
+
continue;
|
|
1881
1888
|
if (i > 0) {
|
|
1882
1889
|
this.line("");
|
|
1883
1890
|
}
|
|
@@ -2174,13 +2181,13 @@ class ConfigValidator {
|
|
|
2174
2181
|
const lineNumber = source.substring(0, position).split(`
|
|
2175
2182
|
`).length;
|
|
2176
2183
|
const line = lines[lineNumber - 1];
|
|
2177
|
-
const fieldMatch = line
|
|
2184
|
+
const fieldMatch = line?.match(/"([^"]+)":\s*{/);
|
|
2178
2185
|
const fieldName = fieldMatch ? fieldMatch[1] : "unknown";
|
|
2179
2186
|
locations.push({
|
|
2180
2187
|
line: lineNumber,
|
|
2181
2188
|
column: match.index - source.lastIndexOf(`
|
|
2182
2189
|
`, position),
|
|
2183
|
-
context: fieldName
|
|
2190
|
+
context: fieldName ?? "unknown"
|
|
2184
2191
|
});
|
|
2185
2192
|
}
|
|
2186
2193
|
this.issues.push({
|
|
@@ -2216,7 +2223,7 @@ class ConfigValidator {
|
|
|
2216
2223
|
loadConfig(configPath) {
|
|
2217
2224
|
delete __require.cache[__require.resolve(path.resolve(configPath))];
|
|
2218
2225
|
const module = __require(path.resolve(configPath));
|
|
2219
|
-
return module.default || module;
|
|
2226
|
+
return module.verificationConfig || module.default || module;
|
|
2220
2227
|
}
|
|
2221
2228
|
validateConfig(config) {
|
|
2222
2229
|
this.findNullPlaceholders(config.state, "state");
|
|
@@ -2273,7 +2280,7 @@ class ConfigValidator {
|
|
|
2273
2280
|
});
|
|
2274
2281
|
}
|
|
2275
2282
|
}
|
|
2276
|
-
if (config.messages.maxTabs !== null) {
|
|
2283
|
+
if (config.messages.maxTabs !== null && config.messages.maxTabs !== undefined) {
|
|
2277
2284
|
if (config.messages.maxTabs < 1) {
|
|
2278
2285
|
this.issues.push({
|
|
2279
2286
|
type: "invalid_value",
|
|
@@ -2374,7 +2381,7 @@ function validateConfig(configPath) {
|
|
|
2374
2381
|
}
|
|
2375
2382
|
|
|
2376
2383
|
// vendor/verify/src/cli.ts
|
|
2377
|
-
var __dirname = "/Users/AJT/projects/polly/
|
|
2384
|
+
var __dirname = "/Users/AJT/projects/polly/vendor/verify/src";
|
|
2378
2385
|
var COLORS = {
|
|
2379
2386
|
reset: "\x1B[0m",
|
|
2380
2387
|
red: "\x1B[31m",
|
|
@@ -2448,7 +2455,7 @@ async function setupCommand() {
|
|
|
2448
2455
|
table.push([field.path, field.type.kind, status]);
|
|
2449
2456
|
}
|
|
2450
2457
|
for (const row of table) {
|
|
2451
|
-
console.log(` ${row[0]
|
|
2458
|
+
console.log(` ${row[0]?.padEnd(32) ?? ""} ${row[1]?.padEnd(22) ?? ""} ${row[2] ?? ""}`);
|
|
2452
2459
|
}
|
|
2453
2460
|
}
|
|
2454
2461
|
const configContent = generateConfig(analysis);
|
|
@@ -2565,9 +2572,9 @@ async function verifyCommand() {
|
|
|
2565
2572
|
async function runFullVerification(configPath) {
|
|
2566
2573
|
const { generateTLA: generateTLA2 } = await Promise.resolve().then(() => exports_tla);
|
|
2567
2574
|
const { DockerRunner: DockerRunner2 } = await Promise.resolve().then(() => (init_docker(), exports_docker));
|
|
2568
|
-
|
|
2569
|
-
const configModule =
|
|
2570
|
-
const config = configModule.default
|
|
2575
|
+
const resolvedPath = path3.resolve(configPath);
|
|
2576
|
+
const configModule = await import(`file://${resolvedPath}?t=${Date.now()}`);
|
|
2577
|
+
const config = configModule.default;
|
|
2571
2578
|
console.log(color("\uD83D\uDCCA Analyzing codebase...", COLORS.blue));
|
|
2572
2579
|
const tsConfigPath = findTsConfig();
|
|
2573
2580
|
if (!tsConfigPath) {
|
|
@@ -2743,4 +2750,4 @@ Stack trace:`, COLORS.gray));
|
|
|
2743
2750
|
process.exit(1);
|
|
2744
2751
|
});
|
|
2745
2752
|
|
|
2746
|
-
//# debugId=
|
|
2753
|
+
//# debugId=C7C70A8E076468AA64756E2164756E21
|