@fairfox/polly 0.18.0 → 0.20.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.
@@ -1784,12 +1784,13 @@ class HandlerExtractor {
1784
1784
  const stateConstraints = [];
1785
1785
  const globalStateConstraints = [];
1786
1786
  const verifiedStates = [];
1787
+ const resources = [];
1787
1788
  this.warnings = [];
1788
1789
  const allSourceFiles = this.project.getSourceFiles();
1789
1790
  const entryPoints = allSourceFiles.filter((f) => this.isWithinPackage(f.getFilePath()));
1790
1791
  this.debugLogSourceFiles(allSourceFiles, entryPoints);
1791
1792
  for (const entryPoint of entryPoints) {
1792
- this.analyzeFileAndImports(entryPoint, handlers, messageTypes, invalidMessageTypes, stateConstraints, globalStateConstraints, verifiedStates);
1793
+ this.analyzeFileAndImports(entryPoint, handlers, messageTypes, invalidMessageTypes, stateConstraints, globalStateConstraints, verifiedStates, resources);
1793
1794
  }
1794
1795
  if (verifiedStates.length > 0) {
1795
1796
  if (process.env["POLLY_DEBUG"]) {
@@ -1821,10 +1822,11 @@ class HandlerExtractor {
1821
1822
  stateConstraints,
1822
1823
  globalStateConstraints,
1823
1824
  verifiedStates,
1825
+ resources,
1824
1826
  warnings: this.warnings
1825
1827
  };
1826
1828
  }
1827
- analyzeFileAndImports(sourceFile, handlers, messageTypes, invalidMessageTypes, stateConstraints, globalStateConstraints, verifiedStates) {
1829
+ analyzeFileAndImports(sourceFile, handlers, messageTypes, invalidMessageTypes, stateConstraints, globalStateConstraints, verifiedStates, resources) {
1828
1830
  const filePath = sourceFile.getFilePath();
1829
1831
  if (this.analyzedFiles.has(filePath)) {
1830
1832
  return;
@@ -1842,6 +1844,20 @@ class HandlerExtractor {
1842
1844
  globalStateConstraints.push(...fileGlobalConstraints);
1843
1845
  const fileVerifiedStates = this.extractVerifiedStatesFromFile(sourceFile);
1844
1846
  verifiedStates.push(...fileVerifiedStates);
1847
+ const fileResources = this.extractResourcesFromFile(sourceFile, filePath);
1848
+ for (const resource of fileResources) {
1849
+ resources.push(resource);
1850
+ const context = this.inferContext(filePath);
1851
+ const syntheticHandlers = this.createResourceHandlers(resource, context);
1852
+ for (const handler of syntheticHandlers) {
1853
+ handlers.push(handler);
1854
+ if (this.isValidTLAIdentifier(handler.messageType)) {
1855
+ messageTypes.add(handler.messageType);
1856
+ } else {
1857
+ invalidMessageTypes.add(handler.messageType);
1858
+ }
1859
+ }
1860
+ }
1845
1861
  const importDeclarations = sourceFile.getImportDeclarations();
1846
1862
  for (const importDecl of importDeclarations) {
1847
1863
  const importedFile = importDecl.getModuleSpecifierSourceFile();
@@ -1853,7 +1869,7 @@ class HandlerExtractor {
1853
1869
  }
1854
1870
  continue;
1855
1871
  }
1856
- this.analyzeFileAndImports(importedFile, handlers, messageTypes, invalidMessageTypes, stateConstraints, globalStateConstraints, verifiedStates);
1872
+ this.analyzeFileAndImports(importedFile, handlers, messageTypes, invalidMessageTypes, stateConstraints, globalStateConstraints, verifiedStates, resources);
1857
1873
  } else if (process.env["POLLY_DEBUG"]) {
1858
1874
  const specifier = importDecl.getModuleSpecifierValue();
1859
1875
  if (!specifier.startsWith("node:") && !this.isNodeModuleImport(specifier)) {
@@ -2212,7 +2228,9 @@ class HandlerExtractor {
2212
2228
  return;
2213
2229
  if (this.tryExtractSetConstructorPattern(fieldPath, right, assignments))
2214
2230
  return;
2215
- this.tryExtractMapConstructorPattern(fieldPath, right, assignments);
2231
+ if (this.tryExtractMapConstructorPattern(fieldPath, right, assignments))
2232
+ return;
2233
+ this.tryExtractSignalDirectValuePattern(fieldPath, right, assignments);
2216
2234
  }
2217
2235
  tryExtractStateFieldPattern(fieldPath, right, assignments) {
2218
2236
  if (!fieldPath.startsWith("state."))
@@ -2331,6 +2349,25 @@ class HandlerExtractor {
2331
2349
  }
2332
2350
  return true;
2333
2351
  }
2352
+ tryExtractSignalDirectValuePattern(fieldPath, right, assignments) {
2353
+ if (!fieldPath.endsWith(".value"))
2354
+ return false;
2355
+ const signalName = fieldPath.slice(0, -6);
2356
+ const literalValue = this.extractValue(right);
2357
+ if (literalValue !== undefined) {
2358
+ assignments.push({ field: signalName, value: literalValue });
2359
+ return true;
2360
+ }
2361
+ if (Node4.isPropertyAccessExpression(right)) {
2362
+ const rightPath = this.getPropertyPath(right);
2363
+ const parts = rightPath.split(".");
2364
+ if (parts.length === 2 && parts[0] !== undefined && parts[1] !== undefined && this.currentFunctionParams.includes(parts[0])) {
2365
+ assignments.push({ field: signalName, value: `param:${parts[1]}` });
2366
+ return true;
2367
+ }
2368
+ }
2369
+ return false;
2370
+ }
2334
2371
  extractSetOperation(newExpr, fieldPath, signalName) {
2335
2372
  const args = newExpr.getArguments();
2336
2373
  if (args.length === 0) {
@@ -2447,11 +2484,11 @@ class HandlerExtractor {
2447
2484
  return null;
2448
2485
  switch (methodName) {
2449
2486
  case "filter":
2450
- return { field: signalName, value: "SelectSeq(@, LAMBDA t: TRUE)" };
2487
+ return { field: signalName, value: "NDET:FILTER" };
2451
2488
  case "map":
2452
- return { field: signalName, value: "[i \\in DOMAIN @ |-> @[i]]" };
2489
+ return { field: signalName, value: "NDET:MAP" };
2453
2490
  case "slice":
2454
- return { field: signalName, value: "SubSeq(@, 1, Len(@))" };
2491
+ return { field: signalName, value: "NDET:FILTER" };
2455
2492
  case "concat":
2456
2493
  return { field: signalName, value: "@ \\o <<payload>>" };
2457
2494
  case "reverse":
@@ -3722,6 +3759,125 @@ class HandlerExtractor {
3722
3759
  }
3723
3760
  return name || funcName;
3724
3761
  }
3762
+ extractResourcesFromFile(sourceFile, filePath) {
3763
+ const resources = [];
3764
+ sourceFile.forEachDescendant((node) => {
3765
+ if (!Node4.isCallExpression(node))
3766
+ return;
3767
+ const resource = this.extractResourcePattern(node, filePath);
3768
+ if (resource) {
3769
+ resources.push(resource);
3770
+ }
3771
+ });
3772
+ return resources;
3773
+ }
3774
+ extractResourcePattern(node, filePath) {
3775
+ const expression = node.getExpression();
3776
+ if (!Node4.isIdentifier(expression))
3777
+ return null;
3778
+ if (expression.getText() !== "$resource")
3779
+ return null;
3780
+ const args = node.getArguments();
3781
+ if (args.length < 2)
3782
+ return null;
3783
+ const nameArg = args[0];
3784
+ if (!nameArg || !Node4.isStringLiteral(nameArg))
3785
+ return null;
3786
+ const name = nameArg.getLiteralValue();
3787
+ const optionsArg = args[1];
3788
+ if (!optionsArg || !Node4.isObjectLiteralExpression(optionsArg))
3789
+ return null;
3790
+ const sourceSignals = this.extractResourceSourceReads(optionsArg);
3791
+ const variableName = this.getVariableNameFromParent(node) || name;
3792
+ if (process.env["POLLY_DEBUG"]) {
3793
+ console.log(`[DEBUG] Found $resource: ${variableName} (name: "${name}") with source signals: [${sourceSignals.join(", ")}]`);
3794
+ }
3795
+ return {
3796
+ name,
3797
+ variableName,
3798
+ filePath,
3799
+ line: node.getStartLineNumber(),
3800
+ sourceSignals
3801
+ };
3802
+ }
3803
+ extractResourceSourceReads(optionsObj) {
3804
+ const signals = [];
3805
+ const sourceProp = optionsObj.getProperty("source");
3806
+ if (!sourceProp || !Node4.isPropertyAssignment(sourceProp))
3807
+ return signals;
3808
+ const sourceInit = sourceProp.getInitializer();
3809
+ if (!sourceInit)
3810
+ return signals;
3811
+ sourceInit.forEachDescendant((node) => {
3812
+ if (!Node4.isPropertyAccessExpression(node))
3813
+ return;
3814
+ const text = node.getText();
3815
+ const match = text.match(/^(\w+)\.value(?:\.(\w+))?$/);
3816
+ if (match) {
3817
+ const signalName = match[1];
3818
+ const fieldName = match[2];
3819
+ if (fieldName) {
3820
+ signals.push(`${signalName}_${fieldName}`);
3821
+ } else {
3822
+ signals.push(signalName);
3823
+ }
3824
+ }
3825
+ });
3826
+ return signals;
3827
+ }
3828
+ createResourceHandlers(resource, context) {
3829
+ const { name, filePath, line } = resource;
3830
+ const location = { file: filePath, line };
3831
+ const fetchStart = {
3832
+ messageType: `${name}_FetchStart`,
3833
+ node: context,
3834
+ assignments: [
3835
+ { field: `${name}_status`, value: "loading" },
3836
+ { field: `${name}_error`, value: false }
3837
+ ],
3838
+ preconditions: [
3839
+ {
3840
+ expression: `${name}_status !== "loading"`,
3841
+ location: { line, column: 0 }
3842
+ }
3843
+ ],
3844
+ postconditions: [],
3845
+ location
3846
+ };
3847
+ const fetchSuccess = {
3848
+ messageType: `${name}_FetchSuccess`,
3849
+ node: context,
3850
+ assignments: [
3851
+ { field: `${name}_status`, value: "success" },
3852
+ { field: `${name}_error`, value: false }
3853
+ ],
3854
+ preconditions: [
3855
+ {
3856
+ expression: `${name}_status === "loading"`,
3857
+ location: { line, column: 0 }
3858
+ }
3859
+ ],
3860
+ postconditions: [],
3861
+ location
3862
+ };
3863
+ const fetchError = {
3864
+ messageType: `${name}_FetchError`,
3865
+ node: context,
3866
+ assignments: [
3867
+ { field: `${name}_status`, value: "error" },
3868
+ { field: `${name}_error`, value: true }
3869
+ ],
3870
+ preconditions: [
3871
+ {
3872
+ expression: `${name}_status === "loading"`,
3873
+ location: { line, column: 0 }
3874
+ }
3875
+ ],
3876
+ postconditions: [],
3877
+ location
3878
+ };
3879
+ return [fetchStart, fetchSuccess, fetchError];
3880
+ }
3725
3881
  }
3726
3882
 
3727
3883
  // tools/analysis/src/extract/integrations.ts
@@ -6052,4 +6208,4 @@ main().catch((_error) => {
6052
6208
  process.exit(1);
6053
6209
  });
6054
6210
 
6055
- //# debugId=345DE519CB00B03D64756E2164756E21
6211
+ //# debugId=877A170E241AB38F64756E2164756E21