@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.
Files changed (48) hide show
  1. package/dist/cli/polly.js +9 -9
  2. package/dist/cli/polly.js.map +4 -4
  3. package/dist/cli/template-utils.js +3 -3
  4. package/dist/cli/template-utils.js.map +3 -3
  5. package/dist/src/shared/state/app-state.d.ts +8 -0
  6. package/dist/vendor/verify/src/cli.js +78 -71
  7. package/dist/vendor/verify/src/cli.js.map +10 -10
  8. package/dist/vendor/verify/src/public-api.d.ts +41 -0
  9. package/dist/vendor/verify/src/public-api.js +26 -0
  10. package/dist/vendor/verify/src/public-api.js.map +10 -0
  11. package/dist/vendor/visualize/src/cli.js +108 -104
  12. package/dist/vendor/visualize/src/cli.js.map +13 -13
  13. package/package.json +15 -2
  14. package/templates/pwa/build.ts.template +37 -37
  15. package/templates/pwa/server.ts.template +53 -53
  16. package/templates/pwa/src/service-worker.ts.template +131 -135
  17. package/templates/pwa/src/shared-worker.ts.template +114 -109
  18. package/dist/shared/state/app-state.d.ts +0 -8
  19. /package/dist/{background → src/background}/api-client.d.ts +0 -0
  20. /package/dist/{background → src/background}/context-menu.d.ts +0 -0
  21. /package/dist/{background → src/background}/index.d.ts +0 -0
  22. /package/dist/{background → src/background}/log-store.d.ts +0 -0
  23. /package/dist/{background → src/background}/message-router.d.ts +0 -0
  24. /package/dist/{background → src/background}/offscreen-manager.d.ts +0 -0
  25. /package/dist/{index.d.ts → src/index.d.ts} +0 -0
  26. /package/dist/{shared → src/shared}/adapters/chrome/context-menus.chrome.d.ts +0 -0
  27. /package/dist/{shared → src/shared}/adapters/chrome/offscreen.chrome.d.ts +0 -0
  28. /package/dist/{shared → src/shared}/adapters/chrome/runtime.chrome.d.ts +0 -0
  29. /package/dist/{shared → src/shared}/adapters/chrome/storage.chrome.d.ts +0 -0
  30. /package/dist/{shared → src/shared}/adapters/chrome/tabs.chrome.d.ts +0 -0
  31. /package/dist/{shared → src/shared}/adapters/chrome/window.chrome.d.ts +0 -0
  32. /package/dist/{shared → src/shared}/adapters/context-menus.adapter.d.ts +0 -0
  33. /package/dist/{shared → src/shared}/adapters/fetch.adapter.d.ts +0 -0
  34. /package/dist/{shared → src/shared}/adapters/index.d.ts +0 -0
  35. /package/dist/{shared → src/shared}/adapters/logger.adapter.d.ts +0 -0
  36. /package/dist/{shared → src/shared}/adapters/offscreen.adapter.d.ts +0 -0
  37. /package/dist/{shared → src/shared}/adapters/runtime.adapter.d.ts +0 -0
  38. /package/dist/{shared → src/shared}/adapters/storage.adapter.d.ts +0 -0
  39. /package/dist/{shared → src/shared}/adapters/tabs.adapter.d.ts +0 -0
  40. /package/dist/{shared → src/shared}/adapters/window.adapter.d.ts +0 -0
  41. /package/dist/{shared → src/shared}/lib/context-helpers.d.ts +0 -0
  42. /package/dist/{shared → src/shared}/lib/context-specific-helpers.d.ts +0 -0
  43. /package/dist/{shared → src/shared}/lib/errors.d.ts +0 -0
  44. /package/dist/{shared → src/shared}/lib/handler-execution-tracker.d.ts +0 -0
  45. /package/dist/{shared → src/shared}/lib/message-bus.d.ts +0 -0
  46. /package/dist/{shared → src/shared}/lib/state.d.ts +0 -0
  47. /package/dist/{shared → src/shared}/lib/test-helpers.d.ts +0 -0
  48. /package/dist/{shared → src/shared}/types/messages.d.ts +0 -0
@@ -68,27 +68,27 @@ class ProjectDetector {
68
68
  if (background) {
69
69
  const file = background.service_worker || background.scripts?.[0] || background.page;
70
70
  if (file) {
71
- entryPoints.background = this.findSourceFile(file);
71
+ entryPoints["background"] = this.findSourceFile(file);
72
72
  }
73
73
  }
74
74
  const contentScripts = manifest.content_scripts;
75
75
  if (contentScripts && contentScripts.length > 0) {
76
76
  const firstScript = contentScripts[0].js?.[0];
77
77
  if (firstScript) {
78
- entryPoints.content = this.findSourceFile(firstScript);
78
+ entryPoints["content"] = this.findSourceFile(firstScript);
79
79
  }
80
80
  }
81
81
  const popup = manifest.action?.default_popup || manifest.browser_action?.default_popup;
82
82
  if (popup) {
83
83
  const jsFile = this.findAssociatedJS(path3.join(this.projectRoot, popup));
84
84
  if (jsFile)
85
- entryPoints.popup = jsFile;
85
+ entryPoints["popup"] = jsFile;
86
86
  }
87
87
  const options = manifest.options_ui?.page || manifest.options_page;
88
88
  if (options) {
89
89
  const jsFile = this.findAssociatedJS(path3.join(this.projectRoot, options));
90
90
  if (jsFile)
91
- entryPoints.options = jsFile;
91
+ entryPoints["options"] = jsFile;
92
92
  }
93
93
  return {
94
94
  type: "chrome-extension",
@@ -112,7 +112,7 @@ class ProjectDetector {
112
112
  for (const candidate of swCandidates) {
113
113
  const fullPath = path3.join(this.projectRoot, candidate);
114
114
  if (fs3.existsSync(fullPath)) {
115
- entryPoints.worker = fullPath;
115
+ entryPoints["worker"] = fullPath;
116
116
  break;
117
117
  }
118
118
  }
@@ -126,7 +126,7 @@ class ProjectDetector {
126
126
  for (const candidate of clientCandidates) {
127
127
  const fullPath = path3.join(this.projectRoot, candidate);
128
128
  if (fs3.existsSync(fullPath)) {
129
- entryPoints.client = fullPath;
129
+ entryPoints["client"] = fullPath;
130
130
  break;
131
131
  }
132
132
  }
@@ -156,7 +156,7 @@ class ProjectDetector {
156
156
  for (const candidate of mainCandidates) {
157
157
  const fullPath = path3.join(this.projectRoot, candidate);
158
158
  if (fs3.existsSync(fullPath) || fs3.existsSync(fullPath.replace(/\.js$/, ".ts"))) {
159
- entryPoints.main = fs3.existsSync(fullPath) ? fullPath : fullPath.replace(/\.js$/, ".ts");
159
+ entryPoints["main"] = fs3.existsSync(fullPath) ? fullPath : fullPath.replace(/\.js$/, ".ts");
160
160
  break;
161
161
  }
162
162
  }
@@ -169,7 +169,7 @@ class ProjectDetector {
169
169
  for (const candidate of rendererCandidates) {
170
170
  const fullPath = path3.join(this.projectRoot, candidate);
171
171
  if (fs3.existsSync(fullPath)) {
172
- entryPoints.renderer = fullPath;
172
+ entryPoints["renderer"] = fullPath;
173
173
  break;
174
174
  }
175
175
  }
@@ -207,13 +207,13 @@ class ProjectDetector {
207
207
  const scoredServers = this.scoreServerCandidates(serverCandidates);
208
208
  if (scoredServers.length > 0) {
209
209
  const best = scoredServers[0];
210
- entryPoints.server = best.path;
210
+ entryPoints["server"] = best.path;
211
211
  if (best.hasWebSocket) {
212
- contextMapping.server = "WebSocket Server";
212
+ contextMapping["server"] = "WebSocket Server";
213
213
  } else if (best.hasHTTP) {
214
- contextMapping.server = "HTTP Server";
214
+ contextMapping["server"] = "HTTP Server";
215
215
  } else {
216
- contextMapping.server = "Server";
216
+ contextMapping["server"] = "Server";
217
217
  }
218
218
  }
219
219
  const clientCandidates = [
@@ -227,8 +227,8 @@ class ProjectDetector {
227
227
  for (const candidate of clientCandidates) {
228
228
  const fullPath = path3.join(this.projectRoot, candidate);
229
229
  if (fs3.existsSync(fullPath)) {
230
- entryPoints.client = fullPath;
231
- contextMapping.client = "Client";
230
+ entryPoints["client"] = fullPath;
231
+ contextMapping["client"] = "Client";
232
232
  break;
233
233
  }
234
234
  }
@@ -367,7 +367,7 @@ class ProjectDetector {
367
367
  for (const candidate of commonEntries) {
368
368
  const fullPath = path3.join(this.projectRoot, candidate);
369
369
  if (fs3.existsSync(fullPath)) {
370
- entryPoints.main = fullPath;
370
+ entryPoints["main"] = fullPath;
371
371
  break;
372
372
  }
373
373
  }
@@ -512,14 +512,14 @@ class ManifestParser {
512
512
  if (background) {
513
513
  const entryFile = background.files[0];
514
514
  if (entryFile) {
515
- entryPoints.background = this.findSourceFile(entryFile);
515
+ entryPoints["background"] = this.findSourceFile(entryFile);
516
516
  }
517
517
  }
518
518
  const contentScripts = this.parseContentScripts();
519
519
  if (contentScripts && contentScripts.length > 0) {
520
- const firstScript = contentScripts[0].js[0];
520
+ const firstScript = contentScripts[0]?.js[0];
521
521
  if (firstScript) {
522
- entryPoints.content = this.findSourceFile(firstScript);
522
+ entryPoints["content"] = this.findSourceFile(firstScript);
523
523
  }
524
524
  }
525
525
  const popup = this.parsePopup();
@@ -527,7 +527,7 @@ class ManifestParser {
527
527
  const htmlPath = path.join(this.baseDir, popup.html);
528
528
  const jsPath = this.findAssociatedJS(htmlPath);
529
529
  if (jsPath) {
530
- entryPoints.popup = jsPath;
530
+ entryPoints["popup"] = jsPath;
531
531
  }
532
532
  }
533
533
  const options = this.parseOptions();
@@ -535,7 +535,7 @@ class ManifestParser {
535
535
  const htmlPath = path.join(this.baseDir, options.page);
536
536
  const jsPath = this.findAssociatedJS(htmlPath);
537
537
  if (jsPath) {
538
- entryPoints.options = jsPath;
538
+ entryPoints["options"] = jsPath;
539
539
  }
540
540
  }
541
541
  const devtools = this.parseDevtools();
@@ -543,7 +543,7 @@ class ManifestParser {
543
543
  const htmlPath = path.join(this.baseDir, devtools.page);
544
544
  const jsPath = this.findAssociatedJS(htmlPath);
545
545
  if (jsPath) {
546
- entryPoints.devtools = jsPath;
546
+ entryPoints["devtools"] = jsPath;
547
547
  }
548
548
  }
549
549
  return entryPoints;
@@ -705,9 +705,9 @@ class ContextAnalyzer {
705
705
  handlers: contextHandlers,
706
706
  chromeAPIs,
707
707
  externalAPIs: [],
708
- components,
708
+ ...components ? { components } : {},
709
709
  dependencies,
710
- description
710
+ ...description ? { description } : {}
711
711
  };
712
712
  }
713
713
  extractChromeAPIs(sourceFile) {
@@ -717,20 +717,23 @@ class ContextAnalyzer {
717
717
  const text = node.getText();
718
718
  if (text.startsWith("chrome.")) {
719
719
  const match = text.match(/^chrome\.([^.(]+(?:\.[^.(]+)?)/);
720
- if (match) {
721
- apis.add(match[1]);
720
+ const api = match?.[1];
721
+ if (api) {
722
+ apis.add(api);
722
723
  }
723
724
  }
724
725
  if (text.startsWith("browser.")) {
725
726
  const match = text.match(/^browser\.([^.(]+(?:\.[^.(]+)?)/);
726
- if (match) {
727
- apis.add(match[1]);
727
+ const api = match?.[1];
728
+ if (api) {
729
+ apis.add(api);
728
730
  }
729
731
  }
730
732
  if (text.includes("bus.adapters.")) {
731
733
  const match = text.match(/bus\.adapters\.([^.(]+)/);
732
- if (match) {
733
- apis.add(match[1]);
734
+ const api = match?.[1];
735
+ if (api) {
736
+ apis.add(api);
734
737
  }
735
738
  }
736
739
  }
@@ -767,13 +770,14 @@ class ContextAnalyzer {
767
770
  if (Node.isFunctionDeclaration(node)) {
768
771
  const name = node.getName();
769
772
  if (name && this.looksLikeComponent(name, node)) {
773
+ const description = this.extractJSDocDescription(node);
770
774
  components.push({
771
775
  name,
772
776
  type: "function",
773
777
  filePath: sourceFile.getFilePath(),
774
778
  line: node.getStartLineNumber(),
775
779
  props: this.extractProps(node),
776
- description: this.extractJSDocDescription(node)
780
+ ...description ? { description } : {}
777
781
  });
778
782
  }
779
783
  }
@@ -782,13 +786,14 @@ class ContextAnalyzer {
782
786
  const initializer = node.getInitializer();
783
787
  if (name && initializer && (Node.isArrowFunction(initializer) || Node.isFunctionExpression(initializer))) {
784
788
  if (this.looksLikeComponent(name, initializer)) {
789
+ const description = this.extractJSDocDescription(node);
785
790
  components.push({
786
791
  name,
787
792
  type: "function",
788
793
  filePath: sourceFile.getFilePath(),
789
794
  line: node.getStartLineNumber(),
790
795
  props: this.extractProps(initializer),
791
- description: this.extractJSDocDescription(node)
796
+ ...description ? { description } : {}
792
797
  });
793
798
  }
794
799
  }
@@ -796,13 +801,14 @@ class ContextAnalyzer {
796
801
  if (Node.isClassDeclaration(node)) {
797
802
  const name = node.getName();
798
803
  if (name && this.looksLikeClassComponent(node)) {
804
+ const description = this.extractJSDocDescription(node);
799
805
  components.push({
800
806
  name,
801
807
  type: "class",
802
808
  filePath: sourceFile.getFilePath(),
803
809
  line: node.getStartLineNumber(),
804
810
  props: this.extractPropsFromClass(node),
805
- description: this.extractJSDocDescription(node)
811
+ ...description ? { description } : {}
806
812
  });
807
813
  }
808
814
  }
@@ -905,9 +911,9 @@ class FlowAnalyzer {
905
911
  messageType,
906
912
  from: sender.context,
907
913
  to: recipients,
908
- trigger: flowMetadata.trigger,
909
- flowName: flowMetadata.flowName,
910
- description: flowMetadata.description,
914
+ ...flowMetadata.trigger ? { trigger: flowMetadata.trigger } : {},
915
+ ...flowMetadata.flowName ? { flowName: flowMetadata.flowName } : {},
916
+ ...flowMetadata.description ? { description: flowMetadata.description } : {},
911
917
  sequence
912
918
  });
913
919
  }
@@ -1218,7 +1224,7 @@ class IntegrationAnalyzer {
1218
1224
  const moduleSpecifier = importDecl.getModuleSpecifierValue();
1219
1225
  if (!moduleSpecifier.startsWith(".") && !moduleSpecifier.startsWith("/")) {
1220
1226
  const packageName = moduleSpecifier.startsWith("@") ? moduleSpecifier.split("/").slice(0, 2).join("/") : moduleSpecifier.split("/")[0];
1221
- if (!seen.has(packageName)) {
1227
+ if (packageName && !seen.has(packageName)) {
1222
1228
  seen.add(packageName);
1223
1229
  scripts.push({
1224
1230
  type: "external-script",
@@ -1284,7 +1290,7 @@ class IntegrationAnalyzer {
1284
1290
  const hostname = parsed.hostname;
1285
1291
  const cleanHost = hostname.replace(/^www\./, "");
1286
1292
  const parts = cleanHost.split(".");
1287
- if (parts.length > 0) {
1293
+ if (parts.length > 0 && parts[0]) {
1288
1294
  return parts[0].charAt(0).toUpperCase() + parts[0].slice(1) + " API";
1289
1295
  }
1290
1296
  } catch {}
@@ -1314,7 +1320,7 @@ class IntegrationAnalyzer {
1314
1320
  }
1315
1321
 
1316
1322
  // vendor/analysis/src/extract/handlers.ts
1317
- import { Project as Project4, SyntaxKind as SyntaxKind3, Node as Node5 } from "ts-morph";
1323
+ import { Project as Project4, SyntaxKind, Node as Node5 } from "ts-morph";
1318
1324
 
1319
1325
  // vendor/analysis/src/extract/relationships.ts
1320
1326
  import { Node as Node4 } from "ts-morph";
@@ -1417,7 +1423,7 @@ class RelationshipExtractor {
1417
1423
  const objectExpr = expr.getExpression();
1418
1424
  const objectName = objectExpr.getText();
1419
1425
  const methodName = expr.getName();
1420
- targetComponent = this.inferComponentFromCall(objectName, methodName);
1426
+ targetComponent = this.inferComponentFromCall(objectName);
1421
1427
  if (!targetComponent) {
1422
1428
  return null;
1423
1429
  }
@@ -1448,7 +1454,7 @@ class RelationshipExtractor {
1448
1454
  rootObject = rootObject.getExpression();
1449
1455
  }
1450
1456
  const objectName = rootObject.getText();
1451
- const targetComponent = this.inferComponentFromCall(objectName, methodName);
1457
+ const targetComponent = this.inferComponentFromCall(objectName);
1452
1458
  if (!targetComponent) {
1453
1459
  return null;
1454
1460
  }
@@ -1485,7 +1491,7 @@ class RelationshipExtractor {
1485
1491
  }
1486
1492
  extractFromFetchCall(callExpr, handlerName) {
1487
1493
  const args = callExpr.getArguments();
1488
- if (args.length === 0) {
1494
+ if (args.length === 0 || !args[0]) {
1489
1495
  return null;
1490
1496
  }
1491
1497
  const urlArg = args[0].getText();
@@ -1504,7 +1510,7 @@ class RelationshipExtractor {
1504
1510
  evidence: [`fetch() call to: ${urlArg}`]
1505
1511
  };
1506
1512
  }
1507
- inferComponentFromCall(objectName, methodName) {
1513
+ inferComponentFromCall(objectName) {
1508
1514
  const mappings = {
1509
1515
  db: "db_client",
1510
1516
  database: "database",
@@ -1581,7 +1587,7 @@ class RelationshipExtractor {
1581
1587
  }
1582
1588
  if (modulePath.includes("/service") || modulePath.includes("/services")) {
1583
1589
  const match = modulePath.match(/\/([^/]+)\.ts$/);
1584
- if (match) {
1590
+ if (match && match[1]) {
1585
1591
  return this.toComponentId(match[1]);
1586
1592
  }
1587
1593
  }
@@ -1666,7 +1672,7 @@ class HandlerExtractor {
1666
1672
  const handlers = [];
1667
1673
  const messageTypes = new Set;
1668
1674
  const sourceFiles = this.project.getSourceFiles();
1669
- if (process.env.POLLY_DEBUG) {
1675
+ if (process.env["POLLY_DEBUG"]) {
1670
1676
  console.log(`[DEBUG] Loaded ${sourceFiles.length} source files`);
1671
1677
  if (sourceFiles.length <= 20) {
1672
1678
  for (const sf of sourceFiles) {
@@ -1681,7 +1687,7 @@ class HandlerExtractor {
1681
1687
  messageTypes.add(handler.messageType);
1682
1688
  }
1683
1689
  }
1684
- if (process.env.POLLY_DEBUG) {
1690
+ if (process.env["POLLY_DEBUG"]) {
1685
1691
  console.log(`[DEBUG] Total handlers extracted: ${handlers.length}`);
1686
1692
  }
1687
1693
  return {
@@ -1798,7 +1804,7 @@ class HandlerExtractor {
1798
1804
  extractVerificationConditions(funcNode, preconditions, postconditions) {
1799
1805
  const body = funcNode.getBody();
1800
1806
  const statements = Node5.isBlock(body) ? body.getStatements() : [body];
1801
- statements.forEach((statement, index) => {
1807
+ statements.forEach((statement) => {
1802
1808
  if (Node5.isExpressionStatement(statement)) {
1803
1809
  const expr = statement.getExpression();
1804
1810
  if (Node5.isCallExpression(expr)) {
@@ -1862,13 +1868,13 @@ class HandlerExtractor {
1862
1868
  if (Node5.isNumericLiteral(node)) {
1863
1869
  return node.getLiteralValue();
1864
1870
  }
1865
- if (node.getKind() === SyntaxKind3.TrueKeyword) {
1871
+ if (node.getKind() === SyntaxKind.TrueKeyword) {
1866
1872
  return true;
1867
1873
  }
1868
- if (node.getKind() === SyntaxKind3.FalseKeyword) {
1874
+ if (node.getKind() === SyntaxKind.FalseKeyword) {
1869
1875
  return false;
1870
1876
  }
1871
- if (node.getKind() === SyntaxKind3.NullKeyword) {
1877
+ if (node.getKind() === SyntaxKind.NullKeyword) {
1872
1878
  return null;
1873
1879
  }
1874
1880
  return;
@@ -1951,7 +1957,7 @@ class HandlerExtractor {
1951
1957
  typeGuards = this.findTypePredicateFunctions(sourceFile);
1952
1958
  this.typeGuardCache.set(sourceFile, typeGuards);
1953
1959
  }
1954
- if (process.env.POLLY_DEBUG) {
1960
+ if (process.env["POLLY_DEBUG"]) {
1955
1961
  console.log(`[DEBUG] File: ${sourceFile.getBaseName()}`);
1956
1962
  console.log(`[DEBUG] Local type guards found: ${typeGuards.size}`);
1957
1963
  if (typeGuards.size > 0) {
@@ -1965,7 +1971,7 @@ class HandlerExtractor {
1965
1971
  const handler = this.extractHandlerFromIfClause(currentIf, typeGuards, context, filePath);
1966
1972
  if (handler) {
1967
1973
  handlers.push(handler);
1968
- if (process.env.POLLY_DEBUG) {
1974
+ if (process.env["POLLY_DEBUG"]) {
1969
1975
  console.log(`[DEBUG] Found handler: ${handler.messageType} at line ${handler.location.line}`);
1970
1976
  }
1971
1977
  }
@@ -1977,7 +1983,7 @@ class HandlerExtractor {
1977
1983
  }
1978
1984
  }
1979
1985
  } catch (error) {
1980
- if (process.env.POLLY_DEBUG) {
1986
+ if (process.env["POLLY_DEBUG"]) {
1981
1987
  console.log(`[DEBUG] Error in extractTypeGuardHandlers: ${error}`);
1982
1988
  }
1983
1989
  }
@@ -1985,7 +1991,8 @@ class HandlerExtractor {
1985
1991
  }
1986
1992
  extractHandlerFromIfClause(ifNode, typeGuards, context, filePath) {
1987
1993
  try {
1988
- const condition = ifNode.getExpression();
1994
+ const ifStmt = ifNode;
1995
+ const condition = ifStmt.getExpression();
1989
1996
  if (!Node5.isCallExpression(condition)) {
1990
1997
  return null;
1991
1998
  }
@@ -1994,32 +2001,32 @@ class HandlerExtractor {
1994
2001
  if (Node5.isIdentifier(funcExpr)) {
1995
2002
  funcName = funcExpr.getText();
1996
2003
  }
1997
- if (process.env.POLLY_DEBUG && funcName) {
2004
+ if (process.env["POLLY_DEBUG"] && funcName) {
1998
2005
  console.log(`[DEBUG] Processing if condition with function: ${funcName}`);
1999
2006
  }
2000
2007
  let messageType = undefined;
2001
2008
  if (funcName && typeGuards.has(funcName)) {
2002
2009
  messageType = typeGuards.get(funcName);
2003
- if (process.env.POLLY_DEBUG) {
2010
+ if (process.env["POLLY_DEBUG"]) {
2004
2011
  console.log(`[DEBUG] Found in local type guards: ${funcName} → ${messageType}`);
2005
2012
  }
2006
2013
  } else if (Node5.isIdentifier(funcExpr)) {
2007
- if (process.env.POLLY_DEBUG) {
2014
+ if (process.env["POLLY_DEBUG"]) {
2008
2015
  console.log(`[DEBUG] Not found locally, trying import resolution for: ${funcName}`);
2009
2016
  }
2010
- messageType = this.resolveImportedTypeGuard(funcExpr);
2017
+ messageType = this.resolveImportedTypeGuard(funcExpr) ?? undefined;
2011
2018
  }
2012
2019
  if (!messageType) {
2013
- if (process.env.POLLY_DEBUG && funcName) {
2020
+ if (process.env["POLLY_DEBUG"] && funcName) {
2014
2021
  console.log(`[DEBUG] Could not resolve message type for: ${funcName}`);
2015
2022
  }
2016
2023
  return null;
2017
2024
  }
2018
- const line = ifNode.getStartLineNumber();
2019
- const sourceFile = ifNode.getSourceFile();
2025
+ const line = ifStmt.getStartLineNumber();
2026
+ const sourceFile = ifStmt.getSourceFile();
2020
2027
  const handlerName = `${messageType}_handler`;
2021
2028
  let relationships = undefined;
2022
- const thenStatement = ifNode.getThenStatement();
2029
+ const thenStatement = ifStmt.getThenStatement();
2023
2030
  if (thenStatement) {
2024
2031
  const detectedRelationships = this.relationshipExtractor.extractFromHandler(thenStatement, sourceFile, handlerName);
2025
2032
  if (detectedRelationships.length > 0) {
@@ -2072,7 +2079,7 @@ class HandlerExtractor {
2072
2079
  const bodyText = body.getText();
2073
2080
  const typeValueMatch = bodyText.match(/\.type\s*===?\s*['"](\w+)['"]/);
2074
2081
  if (typeValueMatch) {
2075
- messageType = typeValueMatch[1];
2082
+ messageType = typeValueMatch[1] ?? null;
2076
2083
  }
2077
2084
  }
2078
2085
  }
@@ -2090,7 +2097,7 @@ class HandlerExtractor {
2090
2097
  const funcName = identifier.getText();
2091
2098
  const definitions = identifier.getDefinitionNodes();
2092
2099
  if (definitions.length === 0) {
2093
- if (process.env.POLLY_DEBUG) {
2100
+ if (process.env["POLLY_DEBUG"]) {
2094
2101
  console.log(`[DEBUG] No definitions found for imported function: ${funcName}`);
2095
2102
  }
2096
2103
  return null;
@@ -2098,7 +2105,7 @@ class HandlerExtractor {
2098
2105
  for (const def of definitions) {
2099
2106
  if (Node5.isFunctionDeclaration(def) || Node5.isFunctionExpression(def) || Node5.isArrowFunction(def)) {
2100
2107
  const returnTypeNode = def.getReturnTypeNode();
2101
- if (process.env.POLLY_DEBUG) {
2108
+ if (process.env["POLLY_DEBUG"]) {
2102
2109
  const returnType = def.getReturnType().getText();
2103
2110
  console.log(`[DEBUG] Function ${funcName} return type (resolved): ${returnType}`);
2104
2111
  console.log(`[DEBUG] Has return type node: ${!!returnTypeNode}`);
@@ -2110,7 +2117,7 @@ class HandlerExtractor {
2110
2117
  const typeName = typeNode.getText();
2111
2118
  const messageType = this.extractMessageTypeFromTypeName(typeName);
2112
2119
  if (messageType) {
2113
- if (process.env.POLLY_DEBUG) {
2120
+ if (process.env["POLLY_DEBUG"]) {
2114
2121
  console.log(`[DEBUG] Resolved ${funcName} → ${messageType} (from AST type predicate)`);
2115
2122
  }
2116
2123
  return messageType;
@@ -2122,8 +2129,8 @@ class HandlerExtractor {
2122
2129
  const bodyText = body.getText();
2123
2130
  const typeValueMatch = bodyText.match(/\.type\s*===?\s*['"](\w+)['"]/);
2124
2131
  if (typeValueMatch) {
2125
- const messageType = typeValueMatch[1];
2126
- if (process.env.POLLY_DEBUG) {
2132
+ const messageType = typeValueMatch[1] ?? null;
2133
+ if (process.env["POLLY_DEBUG"]) {
2127
2134
  console.log(`[DEBUG] Resolved ${funcName} → ${messageType} (from body)`);
2128
2135
  }
2129
2136
  return messageType;
@@ -2132,7 +2139,7 @@ class HandlerExtractor {
2132
2139
  }
2133
2140
  }
2134
2141
  } catch (error) {
2135
- if (process.env.POLLY_DEBUG) {
2142
+ if (process.env["POLLY_DEBUG"]) {
2136
2143
  console.log(`[DEBUG] Error resolving imported type guard: ${error}`);
2137
2144
  }
2138
2145
  }
@@ -2228,9 +2235,9 @@ class ADRExtractor {
2228
2235
  const content = fs2.readFileSync(filePath, "utf-8");
2229
2236
  const fileName = path2.basename(filePath, ".md");
2230
2237
  const idMatch = fileName.match(/^(\d+)/);
2231
- const id = idMatch ? idMatch[1] : fileName;
2238
+ const id = idMatch?.[1] ?? fileName;
2232
2239
  const titleMatch = content.match(/^#\s+(.+)$/m);
2233
- const title = titleMatch ? titleMatch[1].trim() : fileName;
2240
+ const title = titleMatch?.[1]?.trim() ?? fileName;
2234
2241
  const status = this.extractStatus(content);
2235
2242
  const date = this.extractDate(content);
2236
2243
  const context = this.extractSection(content, "Context");
@@ -2251,8 +2258,8 @@ class ADRExtractor {
2251
2258
  context,
2252
2259
  decision,
2253
2260
  consequences,
2254
- alternatives,
2255
- links,
2261
+ ...alternatives && alternatives.length > 0 ? { alternatives } : {},
2262
+ ...links.length > 0 ? { links } : {},
2256
2263
  source: filePath
2257
2264
  };
2258
2265
  }
@@ -2260,20 +2267,20 @@ class ADRExtractor {
2260
2267
  const statusMatch = content.match(/Status:\s*(\w+)/i);
2261
2268
  if (!statusMatch)
2262
2269
  return "accepted";
2263
- const status = statusMatch[1].toLowerCase();
2264
- if (["proposed", "accepted", "deprecated", "superseded"].includes(status)) {
2270
+ const status = statusMatch[1]?.toLowerCase();
2271
+ if (status && ["proposed", "accepted", "deprecated", "superseded"].includes(status)) {
2265
2272
  return status;
2266
2273
  }
2267
2274
  return "accepted";
2268
2275
  }
2269
2276
  extractDate(content) {
2270
2277
  const dateMatch = content.match(/Date:\s*(\d{4}-\d{2}-\d{2})/i) || content.match(/(\d{4}-\d{2}-\d{2})/i);
2271
- return dateMatch ? dateMatch[1] : new Date().toISOString().split("T")[0];
2278
+ return dateMatch?.[1] ?? new Date().toISOString().split("T")[0];
2272
2279
  }
2273
2280
  extractSection(content, sectionName) {
2274
2281
  const regex = new RegExp(`##\\s+${sectionName}\\s*\\n([\\s\\S]*?)(?=\\n##|$)`, "i");
2275
2282
  const match = content.match(regex);
2276
- return match ? match[1].trim() : "";
2283
+ return match?.[1]?.trim() ?? "";
2277
2284
  }
2278
2285
  extractLinks(content) {
2279
2286
  const links = [];
@@ -2281,10 +2288,11 @@ class ADRExtractor {
2281
2288
  if (supersedesMatch) {
2282
2289
  for (const match of supersedesMatch) {
2283
2290
  const idMatch = match.match(/ADR-(\d+)/);
2284
- if (idMatch) {
2291
+ const id = idMatch?.[1];
2292
+ if (id) {
2285
2293
  links.push({
2286
2294
  type: "supersedes",
2287
- adrId: idMatch[1]
2295
+ adrId: id
2288
2296
  });
2289
2297
  }
2290
2298
  }
@@ -2293,10 +2301,11 @@ class ADRExtractor {
2293
2301
  if (supersededByMatch) {
2294
2302
  for (const match of supersededByMatch) {
2295
2303
  const idMatch = match.match(/ADR-(\d+)/);
2296
- if (idMatch) {
2304
+ const id = idMatch?.[1];
2305
+ if (id) {
2297
2306
  links.push({
2298
2307
  type: "superseded-by",
2299
- adrId: idMatch[1]
2308
+ adrId: id
2300
2309
  });
2301
2310
  }
2302
2311
  }
@@ -2327,7 +2336,7 @@ class ArchitectureAnalyzer {
2327
2336
  systemInfo = {
2328
2337
  name: manifest.name,
2329
2338
  version: manifest.version,
2330
- description: manifest.description
2339
+ ...manifest.description ? { description: manifest.description } : {}
2331
2340
  };
2332
2341
  } else {
2333
2342
  const { detectProjectConfig: detectProjectConfig2 } = await Promise.resolve().then(() => (init_project_detector(), exports_project_detector));
@@ -2336,7 +2345,7 @@ class ArchitectureAnalyzer {
2336
2345
  systemInfo = {
2337
2346
  name: projectConfig.metadata?.name || "Unknown Project",
2338
2347
  version: projectConfig.metadata?.version || "0.0.0",
2339
- description: projectConfig.metadata?.description
2348
+ ...projectConfig.metadata?.description ? { description: projectConfig.metadata.description } : {}
2340
2349
  };
2341
2350
  }
2342
2351
  const handlerExtractor = new HandlerExtractor(this.options.tsConfigPath);
@@ -2361,13 +2370,13 @@ class ArchitectureAnalyzer {
2361
2370
  return {
2362
2371
  projectRoot: this.options.projectRoot,
2363
2372
  system: systemInfo,
2364
- manifest,
2365
- projectConfig,
2373
+ ...manifest ? { manifest } : {},
2374
+ ...projectConfig ? { projectConfig } : {},
2366
2375
  contexts,
2367
2376
  messageFlows,
2368
2377
  integrations,
2369
- adrs: adrs.adrs.length > 0 ? adrs : undefined,
2370
- repository
2378
+ ...adrs.adrs.length > 0 ? { adrs } : {},
2379
+ ...repository ? { repository } : {}
2371
2380
  };
2372
2381
  }
2373
2382
  mergeExternalAPIsIntoContexts(contexts, integrations) {
@@ -2578,7 +2587,6 @@ class StructurizrDSLGenerator {
2578
2587
  const parts = [];
2579
2588
  for (const integration of this.analysis.integrations) {
2580
2589
  if (integration.type === "api" || integration.type === "websocket") {
2581
- const tech = integration.technology || (integration.type === "websocket" ? "WebSocket" : "REST API");
2582
2590
  let desc = integration.description || "";
2583
2591
  if (!desc && integration.calls && integration.calls.length > 0) {
2584
2592
  const endpoints = integration.calls.slice(0, 3).map((c) => c.endpoint).join(", ");
@@ -2691,7 +2699,7 @@ class StructurizrDSLGenerator {
2691
2699
  return parts.join(`
2692
2700
  `);
2693
2701
  }
2694
- generateComponentDescription(messageType, handler) {
2702
+ generateComponentDescription(messageType, _handler) {
2695
2703
  const type = messageType.toLowerCase();
2696
2704
  if (type.includes("login")) {
2697
2705
  return "Authenticates users and establishes sessions";
@@ -2721,7 +2729,7 @@ class StructurizrDSLGenerator {
2721
2729
  }
2722
2730
  return `Processes ${messageType} messages and coordinates business logic`;
2723
2731
  }
2724
- getComponentTags(messageType, handler) {
2732
+ getComponentTags(messageType, _handler) {
2725
2733
  const tags = ["Message Handler"];
2726
2734
  const type = messageType.toLowerCase();
2727
2735
  if (type.includes("login") || type.includes("logout") || type.includes("auth")) {
@@ -2780,7 +2788,7 @@ class StructurizrDSLGenerator {
2780
2788
  }
2781
2789
  return properties;
2782
2790
  }
2783
- generateComponentRelationships(contextType, contextInfo) {
2791
+ generateComponentRelationships(_contextType, contextInfo) {
2784
2792
  const parts = [];
2785
2793
  const handlersByType = new Map;
2786
2794
  for (const handler of contextInfo.handlers) {
@@ -2792,7 +2800,7 @@ class StructurizrDSLGenerator {
2792
2800
  if (contextInfo.chromeAPIs && contextInfo.chromeAPIs.length > 0) {
2793
2801
  for (const api of contextInfo.chromeAPIs) {
2794
2802
  const apiId = this.toId(`chrome_${api}`);
2795
- for (const [messageType, handlers] of handlersByType) {
2803
+ for (const [messageType, _handlers] of handlersByType) {
2796
2804
  const componentId = this.toId(this.toComponentName(messageType));
2797
2805
  let description = `Uses ${api}`;
2798
2806
  if (api === "storage") {
@@ -2838,7 +2846,7 @@ class StructurizrDSLGenerator {
2838
2846
  }
2839
2847
  const stateHandlers = [];
2840
2848
  const queryHandlers = [];
2841
- for (const [messageType, handlers] of handlersByType) {
2849
+ for (const [messageType, _handlers] of handlersByType) {
2842
2850
  const type = messageType.toLowerCase();
2843
2851
  const componentId = this.toId(this.toComponentName(messageType));
2844
2852
  if (type.includes("add") || type.includes("create") || type.includes("update") || type.includes("delete") || type.includes("remove") || type.includes("toggle") || type.includes("clear") || type.includes("login") || type.includes("logout")) {
@@ -2994,7 +3002,6 @@ class StructurizrDSLGenerator {
2994
3002
  }
2995
3003
  generateAutomaticDynamicDiagrams() {
2996
3004
  const diagrams = [];
2997
- const processedHandlers = new Set;
2998
3005
  const handlersWithRelationships = [];
2999
3006
  for (const [contextType, contextInfo] of Object.entries(this.analysis.contexts)) {
3000
3007
  for (const handler of contextInfo.handlers) {
@@ -3059,7 +3066,7 @@ class StructurizrDSLGenerator {
3059
3066
  const scope = handlers[0]?.contextName ? `extension.${handlers[0].contextName}` : "extension";
3060
3067
  parts.push(` dynamic ${scope} "${title}" "${description}" {`);
3061
3068
  let stepCount = 0;
3062
- for (const { handler, contextName } of handlers) {
3069
+ for (const { handler, contextName: _contextName } of handlers) {
3063
3070
  const handlerComponentId = this.toId(`${handler.messageType}_handler`);
3064
3071
  for (const rel of handler.relationships) {
3065
3072
  const toComponent = this.toId(rel.to);
@@ -3142,7 +3149,7 @@ class StructurizrDSLGenerator {
3142
3149
  state: "Application state synchronization",
3143
3150
  general: "Message flow through the system"
3144
3151
  };
3145
- return descriptions[domain] || descriptions.general;
3152
+ return descriptions[domain] || descriptions["general"];
3146
3153
  }
3147
3154
  getUserAction(domain) {
3148
3155
  const actions = {
@@ -3151,7 +3158,7 @@ class StructurizrDSLGenerator {
3151
3158
  state: "Requests state",
3152
3159
  general: "Interacts"
3153
3160
  };
3154
- return actions[domain] || actions.general;
3161
+ return actions[domain] || actions["general"];
3155
3162
  }
3156
3163
  getMessageDescription(messageType) {
3157
3164
  const type = messageType.toLowerCase();
@@ -3360,9 +3367,6 @@ class StructurizrDSLGenerator {
3360
3367
  toId(name) {
3361
3368
  return name.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_|_$/g, "");
3362
3369
  }
3363
- toViewName(flowName) {
3364
- return flowName.split(/[_-]/).map((part) => this.capitalize(part)).join(" ");
3365
- }
3366
3370
  capitalize(str) {
3367
3371
  return str.charAt(0).toUpperCase() + str.slice(1);
3368
3372
  }
@@ -3429,12 +3433,12 @@ class StructurizrDSLGenerator {
3429
3433
  let entity = null;
3430
3434
  const underscoreMatch = type.match(/^([a-z]+)_(add|create|update|delete|remove|get|fetch|load|list|query)/);
3431
3435
  if (underscoreMatch) {
3432
- entity = underscoreMatch[1];
3436
+ entity = underscoreMatch[1] ?? null;
3433
3437
  }
3434
3438
  if (!entity) {
3435
3439
  const camelMatch = type.match(/(add|create|update|delete|remove|get|fetch|load|list|query)([a-z]+)/i);
3436
3440
  if (camelMatch) {
3437
- entity = camelMatch[2].toLowerCase();
3441
+ entity = camelMatch[2]?.toLowerCase() ?? null;
3438
3442
  }
3439
3443
  }
3440
3444
  if (!entity && type.match(/^[a-z]+$/)) {
@@ -3811,7 +3815,7 @@ Stack trace:`, COLORS.gray));
3811
3815
  process.exit(1);
3812
3816
  }
3813
3817
  }
3814
- async function exportCommand(args) {
3818
+ async function exportCommand(_args) {
3815
3819
  console.log(color(`
3816
3820
  \uD83D\uDCE4 Generating static site...
3817
3821
  `, COLORS.blue));
@@ -3884,7 +3888,7 @@ async function serveCommand(args) {
3884
3888
  if (!BunGlobal) {
3885
3889
  throw new Error("Bun runtime is required to run the server");
3886
3890
  }
3887
- const server = BunGlobal.serve({
3891
+ BunGlobal.serve({
3888
3892
  port,
3889
3893
  fetch(req) {
3890
3894
  const url = new URL(req.url);
@@ -3999,4 +4003,4 @@ Stack trace:`, COLORS.gray));
3999
4003
  process.exit(1);
4000
4004
  });
4001
4005
 
4002
- //# debugId=701BDB9A33D6395464756E2164756E21
4006
+ //# debugId=3ECE56D6DA69F32764756E2164756E21