@fairfox/polly 0.19.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)) {
@@ -3743,6 +3759,125 @@ class HandlerExtractor {
3743
3759
  }
3744
3760
  return name || funcName;
3745
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
+ }
3746
3881
  }
3747
3882
 
3748
3883
  // tools/analysis/src/extract/integrations.ts
@@ -6073,4 +6208,4 @@ main().catch((_error) => {
6073
6208
  process.exit(1);
6074
6209
  });
6075
6210
 
6076
- //# debugId=D42055AB70D110FF64756E2164756E21
6211
+ //# debugId=877A170E241AB38F64756E2164756E21