Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 0 additions & 85 deletions src/simulator/src/data/backupCircuit.js

This file was deleted.

122 changes: 122 additions & 0 deletions src/simulator/src/data/backupCircuit.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import { projectSavedSet } from './project';
import { moduleList, updateOrder } from '../metadata';

/* eslint-disable no-param-reassign */

// ------------------
// Type Declarations
// ------------------

interface NodeLike {
saveObject: () => Record<string, any>;
}

interface SubCircuitLike {
removeConnections: () => void;
makeConnections: () => void;
}

interface Scope {
SubCircuit: SubCircuitLike[];
allNodes: NodeLike[];
nodes: NodeLike[];
layout: Record<string, any>;
verilogMetadata: Record<string, any>;
testbenchData: Record<string, any>;
id: number;
name: string;
restrictedCircuitElementsUsed: Record<string, any>;
backups: string[];
history: string[];
timeStamp: number;
[key: string]: any; // For dynamic moduleList entries
}
Comment on lines +19 to +33
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Fix type mismatches with the actual Scope class.

The Scope interface has several type inconsistencies with the actual Scope class defined in circuit.ts:

  1. Line 26: id should be number | string (not just number)
  2. Line 28: restrictedCircuitElementsUsed should be any[] (not Record<string, any>)
  3. Lines 20-22: SubCircuit, allNodes, and nodes should be optional properties marked with ?, as they are in the actual Scope class
  4. Line 25: testbenchData is not defined in the Scope class from circuit.ts

Apply this diff to align the interface with the actual Scope class:

 interface Scope {
-  SubCircuit: SubCircuitLike[];
-  allNodes: NodeLike[];
-  nodes: NodeLike[];
+  SubCircuit?: SubCircuitLike[];
+  allNodes?: NodeLike[];
+  nodes?: NodeLike[];
   layout: Record<string, any>;
   verilogMetadata: Record<string, any>;
-  testbenchData: Record<string, any>;
-  id: number;
+  testbenchData?: Record<string, any>;
+  id: number | string;
   name: string;
-  restrictedCircuitElementsUsed: Record<string, any>;
+  restrictedCircuitElementsUsed: any[];
   backups: string[];
   history: string[];
   timeStamp: number;
   [key: string]: any;
 }

Please verify whether testbenchData exists on the Scope class or is dynamically added. Run this script to check:


🏁 Script executed:

#!/bin/bash
# Search for testbenchData usage in the Scope class definition
rg -nP --type=ts -C5 'testbenchData' 'src/simulator/src/circuit.ts'

# Also check where testbenchData is assigned or accessed
rg -nP --type=ts -A3 -B3 '\.testbenchData\s*[=:]'

Length of output: 5108


🏁 Script executed:

#!/bin/bash
# Find the actual Scope class/type definition in circuit.ts
rg -nP --type=ts -A20 'class Scope|interface Scope|type Scope' 'src/simulator/src/circuit.ts' | head -60

# Search for restrictedCircuitElementsUsed to see its actual type
rg -nP --type=ts -B2 -A2 'restrictedCircuitElementsUsed\s*[:=]' 'src/simulator/src/circuit.ts'

# Check id property definition
rg -nP --type=ts -B2 -A2 'this\.id\s*[:=]|id\s*[:=]\s*[0-9]|id\s*[:=]\s*string' 'src/simulator/src/circuit.ts' | head -40

Length of output: 2101


🏁 Script executed:

#!/bin/bash
# Check if SubCircuit is used elsewhere or if it's CircuitElement
rg -nP --type=ts -B3 -A3 'SubCircuit' 'src/simulator/src/data/backupCircuit.ts'

# Check how the Scope interface is actually used in backupCircuit.ts
rg -nP --type=ts -B5 -A5 'interface Scope' 'src/simulator/src/data/backupCircuit.ts'

# See the full context of backupCircuit.ts
cat 'src/simulator/src/data/backupCircuit.ts' | head -100

Length of output: 3424


Fix critical type mismatches and incompatibility with the actual Scope class.

The Scope interface has several serious type inconsistencies with the actual Scope class in circuit.ts:

  1. Line 20: SubCircuit property doesn't exist in the Scope class—it has CircuitElement instead. The backUp() function (lines 67, 95) will fail at runtime trying to access scope.SubCircuit.
  2. Line 26: id should be number | string (not just number)
  3. Line 28: restrictedCircuitElementsUsed should be any[] (not Record<string, any>)
  4. Lines 21–22: allNodes and nodes should be optional (marked with ?)

The testbenchData property (line 25) is intentionally included and actively used in the backup logic (line 73, 85), so it should remain.

Apply this diff:

 interface Scope {
-  SubCircuit: SubCircuitLike[];
+  CircuitElement?: SubCircuitLike[];
   allNodes?: NodeLike[];
   nodes?: NodeLike[];
   layout: Record<string, any>;
   verilogMetadata: Record<string, any>;
   testbenchData: Record<string, any>;
-  id: number;
+  id: number | string;
   name: string;
-  restrictedCircuitElementsUsed: Record<string, any>;
+  restrictedCircuitElementsUsed: any[];
   backups: string[];
   history: string[];
   timeStamp: number;
   [key: string]: any;
 }

Then update the backUp() function loops (lines 67, 95) to iterate over scope.CircuitElement instead of scope.SubCircuit.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/simulator/src/data/backupCircuit.ts around lines 19 to 33, the Scope
interface does not match the real Scope class: change SubCircuit to
CircuitElement: SubCircuit: SubCircuitLike[] -> remove and add CircuitElement?:
CircuitElementLike[] (or CircuitElement: CircuitElementLike[] if required by
class), make allNodes? and nodes? optional (add ?), change id: number -> id:
number | string, change restrictedCircuitElementsUsed: Record<string, any> ->
restrictedCircuitElementsUsed: any[], keep testbenchData as-is. Then update the
backUp() function loops at lines ~67 and ~95 to iterate over
scope.CircuitElement instead of scope.SubCircuit so runtime access matches the
actual class.


// Global declaration (CircuitVerse uses globalScope)
declare const globalScope: Scope;

// ------------------
// Helper Functions
// ------------------

function extract(obj: NodeLike): Record<string, any> {
return obj.saveObject();
}

/**
* Check if backup is available
* @param scope Circuit scope
* @returns true if any data exists for backup
* @category data
*/
export function checkIfBackup(scope: Scope): boolean {
for (let i = 0; i < updateOrder.length; i++) {
const key = updateOrder[i];
if (scope[key]?.length) return true;
}
return false;
}

/**
* Create a serialized backup of the current circuit state.
* @param scope Current working scope (defaults to globalScope)
* @returns JSON-compatible backup data object
*/
export function backUp(scope: Scope = globalScope): Record<string, any> {
// Disconnect subcircuits before saving
for (const sub of scope.SubCircuit) {
sub.removeConnections();
}
Comment on lines +67 to +69
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Add guard for optional SubCircuit property.

Since SubCircuit is an optional property on the Scope class, attempting to iterate over it without checking if it exists will cause a runtime error.

Apply this diff to add a safe guard:

   // Disconnect subcircuits before saving
-  for (const sub of scope.SubCircuit) {
-    sub.removeConnections();
+  if (scope.SubCircuit) {
+    for (const sub of scope.SubCircuit) {
+      sub.removeConnections();
+    }
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
for (const sub of scope.SubCircuit) {
sub.removeConnections();
}
// Disconnect subcircuits before saving
if (scope.SubCircuit) {
for (const sub of scope.SubCircuit) {
sub.removeConnections();
}
}
🤖 Prompt for AI Agents
In src/simulator/src/data/backupCircuit.ts around lines 67 to 69, the code
iterates over scope.SubCircuit which is optional on Scope; add a guard to check
that scope.SubCircuit exists and is iterable before looping (e.g., if
(scope.SubCircuit && Array.isArray(scope.SubCircuit)) or if
(scope.SubCircuit?.length) ), and only then call sub.removeConnections() for
each element; keep the existing behavior otherwise.


const data: Record<string, any> = {
layout: scope.layout,
verilogMetadata: scope.verilogMetadata,
allNodes: scope.allNodes.map(extract),
testbenchData: scope.testbenchData,
id: scope.id,
name: scope.name,
};

// Save all module objects dynamically
for (const moduleName of moduleList) {
if (scope[moduleName]?.length) {
data[moduleName] = scope[moduleName].map(extract);
}
}
Comment on lines +71 to +85
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Add guards for optional properties.

The code accesses optional properties without checking if they exist:

  1. Line 74: allNodes is optional and could be undefined
  2. Line 75: testbenchData might not exist on the Scope

Apply this diff to add safe guards:

   const data: Record<string, any> = {
     layout: scope.layout,
     verilogMetadata: scope.verilogMetadata,
-    allNodes: scope.allNodes.map(extract),
-    testbenchData: scope.testbenchData,
+    allNodes: scope.allNodes?.map(extract) || [],
+    testbenchData: scope.testbenchData || {},
     id: scope.id,
     name: scope.name,
   };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const data: Record<string, any> = {
layout: scope.layout,
verilogMetadata: scope.verilogMetadata,
allNodes: scope.allNodes.map(extract),
testbenchData: scope.testbenchData,
id: scope.id,
name: scope.name,
};
// Save all module objects dynamically
for (const moduleName of moduleList) {
if (scope[moduleName]?.length) {
data[moduleName] = scope[moduleName].map(extract);
}
}
const data: Record<string, any> = {
layout: scope.layout,
verilogMetadata: scope.verilogMetadata,
allNodes: scope.allNodes?.map(extract) || [],
testbenchData: scope.testbenchData || {},
id: scope.id,
name: scope.name,
};
// Save all module objects dynamically
for (const moduleName of moduleList) {
if (scope[moduleName]?.length) {
data[moduleName] = scope[moduleName].map(extract);
}
}
🤖 Prompt for AI Agents
In src/simulator/src/data/backupCircuit.ts around lines 71 to 85, the code maps
scope.allNodes and reads scope.testbenchData without guarding for undefined;
update the construction of data so optional properties are safely handled—use
default empty array when mapping (e.g., treat allNodes as an empty array if
undefined) and set testbenchData to a safe default (null/undefined or an empty
object) when absent; keep the existing dynamic module loop but ensure each
scope[moduleName] access is also guarded (only map when it exists and is an
array).


data.restrictedCircuitElementsUsed = scope.restrictedCircuitElementsUsed;

// Save intermediate nodes (wire nodes)
data.nodes = scope.nodes.map(node =>
scope.allNodes.indexOf(node)
);
Comment on lines +90 to +92
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Add guards for optional nodes property.

The nodes property is optional on the Scope class. Attempting to map over it without checking will cause a runtime error.

Apply this diff:

   // Save intermediate nodes (wire nodes)
-  data.nodes = scope.nodes.map(node =>
-    scope.allNodes.indexOf(node)
-  );
+  data.nodes = scope.nodes?.map(node =>
+    scope.allNodes?.indexOf(node) ?? -1
+  ) || [];
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
data.nodes = scope.nodes.map(node =>
scope.allNodes.indexOf(node)
);
data.nodes = scope.nodes?.map(node =>
scope.allNodes?.indexOf(node) ?? -1
) || [];
🤖 Prompt for AI Agents
In src/simulator/src/data/backupCircuit.ts around lines 90 to 92, the code maps
scope.nodes without guarding for scope.nodes being optional; update this to
first check whether scope.nodes is present before mapping (e.g., set data.nodes
to an empty array or undefined when scope.nodes is missing), and only call
scope.nodes.map when scope.nodes is defined to avoid runtime errors.


// Reconnect subcircuits after saving
for (const sub of scope.SubCircuit) {
sub.makeConnections();
}
Comment on lines +95 to +97
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Add guard for optional SubCircuit property.

Same issue as the disconnection code—need to check if SubCircuit exists before iterating.

Apply this diff:

   // Reconnect subcircuits after saving
-  for (const sub of scope.SubCircuit) {
-    sub.makeConnections();
+  if (scope.SubCircuit) {
+    for (const sub of scope.SubCircuit) {
+      sub.makeConnections();
+    }
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
for (const sub of scope.SubCircuit) {
sub.makeConnections();
}
// Reconnect subcircuits after saving
if (scope.SubCircuit) {
for (const sub of scope.SubCircuit) {
sub.makeConnections();
}
}
🤖 Prompt for AI Agents
In src/simulator/src/data/backupCircuit.ts around lines 95 to 97, the loop
assumes scope.SubCircuit always exists; add a guard to check that SubCircuit is
defined (and is iterable) before iterating and calling sub.makeConnections(),
e.g. return early or wrap the for loop in an if (scope.SubCircuit) / if
(Array.isArray(scope.SubCircuit)) check so you don't iterate over undefined.


return data;
}

/**
* Schedule a new backup in the current scope.
* Ensures duplicates aren’t stored consecutively.
* @param scope Current scope (default = globalScope)
* @returns The serialized backup string
*/
export function scheduleBackup(scope: Scope = globalScope): string {
const backup = JSON.stringify(backUp(scope));

if (
scope.backups.length === 0 ||
scope.backups[scope.backups.length - 1] !== backup
) {
scope.backups.push(backup);
scope.history = [];
scope.timeStamp = Date.now();
projectSavedSet(false);
}

return backup;
}