Skip to content

fix: improve node deletion logic reliability#946

Open
subhamkumarr wants to merge 5 commits intoCircuitVerse:mainfrom
subhamkumarr:fix/node-deletion-bug
Open

fix: improve node deletion logic reliability#946
subhamkumarr wants to merge 5 commits intoCircuitVerse:mainfrom
subhamkumarr:fix/node-deletion-bug

Conversation

@subhamkumarr
Copy link

@subhamkumarr subhamkumarr commented Feb 15, 2026

Problem

The node deletion logic had an uncertain comment // Hope this works! - Can cause bugs indicating potential issues. The code was trying to remove nodes from root.nodeList, but nodes are actually added to this.parent.nodeList in the constructor, creating a mismatch.

Solution

  • ✅ Fixed node deletion to remove from correct parent's nodeList
  • ✅ Added validation to ensure nodeList exists and is an array
  • ✅ Use indexOf + splice for reliable removal with filter fallback
  • ✅ Also check root.nodeList for safety and backward compatibility
  • ✅ Removed uncertain comment

Root Cause

  • Nodes are added to this.parent.nodeList in constructor (line 167)
  • But deletion tried to remove from this.parent.scope.root.nodeList (line 940)
  • This mismatch could cause nodes to not be properly removed
  • Could lead to memory leaks or orphaned references

Changes Made

Before:
this.parent.scope.root.nodeList = this.parent.scope.root.nodeList.filter(x => x !== this) // Hope this works! - Can cause bugs

After:

  • Remove from this.parent.nodeList (where node was actually added)
  • Validate that nodeList exists and is an array
  • Use indexOf + splice for reliable removal
    Also check root.nodeList as safety measure

Files Changed

  • src/simulator/src/node.js
  • v1/src/simulator/src/node.js

Testing

✅ Applied fix to both v0 and v1 versions
✅ No linting errors
✅ More reliable node deletion with proper validation
Fixes #945

Summary by CodeRabbit

  • Bug Fixes
    • Fixed crashes and responsiveness for clock timer and enable controls via debounced updates.
    • Prevented improper direct mutation of input values; components now emit changes to parents correctly.
    • Improved detection and removal of orphaned simulator nodes to avoid stray elements.
    • Strengthened node deletion to respect parent/child relationships and improve stability.

- Add debouncing (300ms) for changeClockTime and changeClockEnable
- Skip heavy canvas updates (scheduleUpdate, updateCanvasSet, wireToBeCheckedSet) for clock properties
- Clock changes now only update clock interval/state, not entire canvas
- Fixes continuous resetup() calls that caused crashes
- Applied to both v0 and v1 versions

Fixes: Clock timer and clock enable crash issue in Project Properties Panel
- Remove direct prop mutation (props.propertyValue = value)
- Props are readonly in Vue 3, causing console warnings
- Input value is already updated and change event is triggered
- Fixes Vue warnings: 'Set operation on key propertyValue failed: target is readonly'
- Remove removeBugNodes() function that was a temporary workaround
- Replace with targeted cleanup that only removes orphaned nodes
- Fix root cause: input/output nodes with scope.root parent are now properly identified and removed
- Use reverse iteration for safer array modification
- Applied to both v0 and v1 versions

The new approach:
- Only removes input/output nodes (type 0, 1) that have scope.root as parent
- These nodes should have been replaced with nodes having proper CircuitElement parents
- More efficient and clearer than the original loop-based approach

Fixes CircuitVerse#943
- Fix node deletion from nodeList to use correct parent reference
- Remove from this.parent.nodeList (where node was added) instead of always root.nodeList
- Add validation to ensure nodeList exists and is an array before filtering
- Use indexOf + splice for more reliable removal with fallback to filter
- Also check and remove from root.nodeList for safety/backward compatibility
- Remove uncertain comment 'Hope this works! - Can cause bugs'

The previous code tried to remove from root.nodeList, but nodes are actually
added to this.parent.nodeList in the constructor. This mismatch could cause
nodes to not be properly removed, leading to memory leaks or orphaned references.

Fixes #[ISSUE_NUMBER]
@netlify
Copy link

netlify bot commented Feb 15, 2026

Deploy Preview for circuitverse ready!

Name Link
🔨 Latest commit f3b651f
🔍 Latest deploy log https://app.netlify.com/projects/circuitverse/deploys/6992879ec718ea000862fc10
😎 Deploy Preview https://deploy-preview-946--circuitverse.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
Lighthouse
Lighthouse
1 paths audited
Performance: 45 (🔴 down 1 from production)
Accessibility: 73 (🟢 up 7 from production)
Best Practices: 92 (no change from production)
SEO: 82 (no change from production)
PWA: -
View the detailed breakdown and full score reports

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 15, 2026

Walkthrough

Updates across simulator and UI: Node.delete() now removes nodes from the node’s parent.nodeList with a safe fallback and still cleans root.nodeList; ux.js adds debounce timers and special-case handling to debounce clock time and clock enable property updates; load.js removes the removeBugNodes helper and instead explicitly scans and deletes orphaned input/output nodes after loading; InputGroups.vue no longer mutates the public propertyValue prop in increaseValue/decreaseValue; minor comment updates in ProjectProperty.vue.

🚥 Pre-merge checks | ✅ 3 | ❌ 3

❌ Failed checks (3 warnings)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The PR includes significant out-of-scope changes beyond issue #945 requirements: debounce logic for clock properties (ux.js), orphan cleanup refactoring (load.js), prop mutation fixes (InputGroups.vue), and documentation updates unrelated to node deletion. Consider splitting into focused PR for node deletion fix (#945) and separate PRs for clock debouncing, orphan cleanup, and prop mutation improvements to maintain clear scope and easier review.
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Merge Conflict Detection ⚠️ Warning ❌ Merge conflicts detected (147 files):

⚔️ .github/workflows/Tauri-Release.yml (content)
⚔️ package-lock.json (content)
⚔️ package.json (content)
⚔️ src-tauri/Cargo.toml (content)
⚔️ src-tauri/tauri.conf.json (content)
⚔️ src/assets/constants/theme.ts (content)
⚔️ src/components/Navbar/QuickButton/QuickButton.ts (content)
⚔️ src/components/Panels/ElementsPanel/ElementsPanel.ts (content)
⚔️ src/components/Panels/PropertiesPanel/ModuleProperty/ProjectProperty/ProjectProperty.vue (content)
⚔️ src/components/Panels/PropertiesPanel/PropertiesPanel.ts (content)
⚔️ src/components/Panels/Shared/InputGroups.vue (content)
⚔️ src/components/Panels/TimingDiagramPanel/TimingDiagramPanel.ts (content)
⚔️ src/env.d.ts (content)
⚔️ src/globalVariables.ts (content)
⚔️ src/locales/i18n.ts (content)
⚔️ src/main.ts (content)
⚔️ src/plugins/vuetify.ts (content)
⚔️ src/plugins/webfontloader.ts (content)
⚔️ src/router/index.ts (content)
⚔️ src/shims-vuetify.d.ts (content)
⚔️ src/simulator/spec/vitestSetup.ts (content)
⚔️ src/simulator/src/app.ts (content)
⚔️ src/simulator/src/backgroundArea.ts (content)
⚔️ src/simulator/src/circuit.ts (content)
⚔️ src/simulator/src/contention.ts (content)
⚔️ src/simulator/src/data/load.js (content)
⚔️ src/simulator/src/data/project.ts (content)
⚔️ src/simulator/src/data/redo.ts (content)
⚔️ src/simulator/src/data/saveImage.ts (content)
⚔️ src/simulator/src/data/undo.ts (content)
⚔️ src/simulator/src/drag.ts (content)
⚔️ src/simulator/src/eventQueue.ts (content)
⚔️ src/simulator/src/hotkey_binder/defaultKeys.ts (content)
⚔️ src/simulator/src/hotkey_binder/model/actions.ts (content)
⚔️ src/simulator/src/hotkey_binder/model/addShortcut.ts (content)
⚔️ src/simulator/src/hotkey_binder/model/model.types.ts (content)
⚔️ src/simulator/src/hotkey_binder/model/shortcuts.plugin.ts (content)
⚔️ src/simulator/src/hotkey_binder/model/utils.ts (content)
⚔️ src/simulator/src/interface/backgroundArea.ts (content)
⚔️ src/simulator/src/interface/simulationArea.ts (content)
⚔️ src/simulator/src/layout/layoutBuffer.ts (content)
⚔️ src/simulator/src/layout/layoutNode.ts (content)
⚔️ src/simulator/src/layoutMode.ts (content)
⚔️ src/simulator/src/metadata.ts (content)
⚔️ src/simulator/src/modules/OrGate.ts (content)
⚔️ src/simulator/src/node.js (content)
⚔️ src/simulator/src/quinMcCluskey.ts (content)
⚔️ src/simulator/src/sequential.ts (content)
⚔️ src/simulator/src/simulationArea.ts (content)
⚔️ src/simulator/src/testbench.ts (content)
⚔️ src/simulator/src/themer/customThemeAbstraction.ts (content)
⚔️ src/simulator/src/themer/themeCardSvg.ts (content)
⚔️ src/simulator/src/themer/themer.ts (content)
⚔️ src/simulator/src/themer/themer.types.ts (content)
⚔️ src/simulator/src/themer/themes.ts (content)
⚔️ src/simulator/src/tutorials.ts (content)
⚔️ src/simulator/src/types/app.types.ts (content)
⚔️ src/simulator/src/utils.ts (content)
⚔️ src/simulator/src/ux.js (content)
⚔️ src/simulator/src/wire.ts (content)
⚔️ src/store/SimulatorStore/SimulatorStore.ts (content)
⚔️ src/store/SimulatorStore/actions.ts (content)
⚔️ src/store/SimulatorStore/getters.ts (content)
⚔️ src/store/SimulatorStore/state.ts (content)
⚔️ src/store/authStore.ts (content)
⚔️ src/store/extractStore.ts (content)
⚔️ src/store/layoutStore.ts (content)
⚔️ src/store/projectStore.ts (content)
⚔️ src/store/promptStore.ts (content)
⚔️ src/store/propertiesPanelStore.ts (content)
⚔️ src/store/simulatorMobileStore.ts (content)
⚔️ src/store/testBenchStore.ts (content)
⚔️ src/store/timingDiagramPanelStore.ts (content)
⚔️ src/store/verilogStore.ts (content)
⚔️ v1/src/assets/constants/theme.ts (content)
⚔️ v1/src/components/Navbar/QuickButton/QuickButton.ts (content)
⚔️ v1/src/components/Panels/ElementsPanel/ElementsPanel.ts (content)
⚔️ v1/src/components/Panels/PropertiesPanel/ModuleProperty/ProjectProperty/ProjectProperty.vue (content)
⚔️ v1/src/components/Panels/PropertiesPanel/PropertiesPanel.ts (content)
⚔️ v1/src/components/Panels/Shared/InputGroups.vue (content)
⚔️ v1/src/components/Panels/TimingDiagramPanel/TimingDiagramPanel.ts (content)
⚔️ v1/src/env.d.ts (content)
⚔️ v1/src/globalVariables.ts (content)
⚔️ v1/src/locales/i18n.ts (content)
⚔️ v1/src/main.ts (content)
⚔️ v1/src/plugins/vuetify.ts (content)
⚔️ v1/src/plugins/webfontloader.ts (content)
⚔️ v1/src/router/index.ts (content)
⚔️ v1/src/shims-vuetify.d.ts (content)
⚔️ v1/src/simulator/spec/vitestSetup.ts (content)
⚔️ v1/src/simulator/src/app.ts (content)
⚔️ v1/src/simulator/src/backgroundArea.ts (content)
⚔️ v1/src/simulator/src/circuit.ts (content)
⚔️ v1/src/simulator/src/contention.ts (content)
⚔️ v1/src/simulator/src/data/load.js (content)
⚔️ v1/src/simulator/src/data/project.ts (content)
⚔️ v1/src/simulator/src/data/redo.ts (content)
⚔️ v1/src/simulator/src/data/saveImage.ts (content)
⚔️ v1/src/simulator/src/data/undo.ts (content)
⚔️ v1/src/simulator/src/drag.ts (content)
⚔️ v1/src/simulator/src/eventQueue.ts (content)
⚔️ v1/src/simulator/src/hotkey_binder/defaultKeys.ts (content)
⚔️ v1/src/simulator/src/hotkey_binder/model/actions.ts (content)
⚔️ v1/src/simulator/src/hotkey_binder/model/addShortcut.ts (content)
⚔️ v1/src/simulator/src/hotkey_binder/model/model.types.ts (content)
⚔️ v1/src/simulator/src/hotkey_binder/model/shortcuts.plugin.ts (content)
⚔️ v1/src/simulator/src/hotkey_binder/model/utils.ts (content)
⚔️ v1/src/simulator/src/interface/backgroundArea.ts (content)
⚔️ v1/src/simulator/src/interface/simulationArea.ts (content)
⚔️ v1/src/simulator/src/layout/layoutBuffer.ts (content)
⚔️ v1/src/simulator/src/layout/layoutNode.ts (content)
⚔️ v1/src/simulator/src/layoutMode.ts (content)
⚔️ v1/src/simulator/src/metadata.ts (content)
⚔️ v1/src/simulator/src/modules/OrGate.ts (content)
⚔️ v1/src/simulator/src/node.js (content)
⚔️ v1/src/simulator/src/quinMcCluskey.ts (content)
⚔️ v1/src/simulator/src/sequential.ts (content)
⚔️ v1/src/simulator/src/simulationArea.ts (content)
⚔️ v1/src/simulator/src/testbench.ts (content)
⚔️ v1/src/simulator/src/themer/customThemeAbstraction.ts (content)
⚔️ v1/src/simulator/src/themer/themeCardSvg.ts (content)
⚔️ v1/src/simulator/src/themer/themer.ts (content)
⚔️ v1/src/simulator/src/themer/themer.types.ts (content)
⚔️ v1/src/simulator/src/themer/themes.ts (content)
⚔️ v1/src/simulator/src/tutorials.ts (content)
⚔️ v1/src/simulator/src/types/app.types.ts (content)
⚔️ v1/src/simulator/src/utils.ts (content)
⚔️ v1/src/simulator/src/ux.js (content)
⚔️ v1/src/simulator/src/wire.ts (content)
⚔️ v1/src/store/SimulatorStore/SimulatorStore.ts (content)
⚔️ v1/src/store/SimulatorStore/actions.ts (content)
⚔️ v1/src/store/SimulatorStore/getters.ts (content)
⚔️ v1/src/store/SimulatorStore/state.ts (content)
⚔️ v1/src/store/authStore.ts (content)
⚔️ v1/src/store/extractStore.ts (content)
⚔️ v1/src/store/layoutStore.ts (content)
⚔️ v1/src/store/projectStore.ts (content)
⚔️ v1/src/store/promptStore.ts (content)
⚔️ v1/src/store/propertiesPanelStore.ts (content)
⚔️ v1/src/store/simulatorMobileStore.ts (content)
⚔️ v1/src/store/testBenchStore.ts (content)
⚔️ v1/src/store/timingDiagramPanelStore.ts (content)
⚔️ version/config.ts (content)
⚔️ version/main.ts (content)
⚔️ version/versionLoader.ts (content)
⚔️ vite.config.ts (content)
⚔️ vitest.workspace.ts (content)

These conflicts must be resolved before merging into main.
Resolve conflicts locally and push changes to this branch.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'fix: improve node deletion logic reliability' directly aligns with the main objective of fixing node deletion logic, though it doesn't capture the full scope of debouncing improvements and orphan cleanup changes also present in the changeset.
Linked Issues check ✅ Passed The PR successfully addresses all coding requirements from issue #945: removes uncertain comment, aligns deletion with parent.nodeList where nodes are added, adds validation for nodeList existence/type, and maintains backward compatibility with root.nodeList checks.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
⚔️ Resolve merge conflicts (beta)
  • Auto-commit resolved conflicts to branch fix/node-deletion-bug
  • Post resolved changes as copyable diffs in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@v1/src/simulator/src/data/load.js`:
- Around line 87-91: Update the misleading JSDoc/deprecation comment to reflect
current behavior: remove or replace the phrase "only intermediate nodes are
loaded before modules" and state that all nodes are loaded first (via
data.allNodes.map((x) => loadNode(x, scope))) and orphaned nodes are cleaned up;
reference loadNode and data.allNodes.map to clarify where this loading happens
and keep the category/data deprecation note accurate.
🧹 Nitpick comments (3)
src/simulator/src/node.js (1)

940-961: Redundant double-removal when this.parent === scope.root.

When a node's parent is scope.root (e.g., intermediate nodes converted via converToIntermediate), lines 943–950 already remove it from this.parent.nodeList (which is root.nodeList). Then lines 955–961 attempt to remove the same node from root.nodeList again. The second indexOf will return -1, so it's safe, but the duplication is unnecessary.

Also, the else fallback at line 948–950 is effectively dead code — Array.prototype.indexOf always works correctly for object identity checks in JS. The comment "if indexOf doesn't work" is misleading.

Consider simplifying:

♻️ Suggested simplification
-        // Remove node from parent's nodeList (where it was originally added)
-        // Input/output nodes (type 0, 1) are added to parent.nodeList in constructor (line 167)
-        // We need to remove from the correct parent's nodeList, not always from root.nodeList
-        if (this.parent && this.parent.nodeList && Array.isArray(this.parent.nodeList)) {
-            const index = this.parent.nodeList.indexOf(this)
-            if (index !== -1) {
-                this.parent.nodeList.splice(index, 1)
-            } else {
-                // Fallback: use filter if indexOf doesn't work (shouldn't happen, but safer)
-                this.parent.nodeList = this.parent.nodeList.filter(x => x !== this)
-            }
-        }
-
-        // Also remove from root.nodeList if present (for safety and backward compatibility)
-        // Some edge cases might have nodes in root.nodeList
-        if (this.parent && this.parent.scope && this.parent.scope.root && 
-            this.parent.scope.root.nodeList && Array.isArray(this.parent.scope.root.nodeList)) {
-            const rootIndex = this.parent.scope.root.nodeList.indexOf(this)
-            if (rootIndex !== -1) {
-                this.parent.scope.root.nodeList.splice(rootIndex, 1)
-            }
-        }
+        // Remove node from parent's nodeList (where it was added in constructor)
+        if (this.parent.nodeList && Array.isArray(this.parent.nodeList)) {
+            const index = this.parent.nodeList.indexOf(this)
+            if (index !== -1) {
+                this.parent.nodeList.splice(index, 1)
+            }
+        }
+
+        // Also remove from root.nodeList if parent differs from root (backward compatibility)
+        const root = this.parent.scope.root
+        if (root !== this.parent && root.nodeList && Array.isArray(root.nodeList)) {
+            const rootIndex = root.nodeList.indexOf(this)
+            if (rootIndex !== -1) {
+                root.nodeList.splice(rootIndex, 1)
+            }
+        }
v1/src/simulator/src/data/load.js (1)

125-149: Orphan cleanup logic is correct but relies on a subtle ordering invariant.

The reverse-order index collection (line 132) combined with forward iteration of nodesToRemove (line 145) ensures that node.delete() — which uses filter to shrink allNodes — doesn't invalidate subsequent indices. This works because higher indices are processed first.

This is correct but fragile. If anyone later changes the iteration order or the way delete() modifies allNodes, it could silently break. A brief inline comment would help future maintainers.

📝 Suggested clarifying comment
     // Remove orphaned nodes in reverse order to maintain indices
+    // (nodesToRemove is already sorted descending because the scan loop runs from high to low)
     for (const index of nodesToRemove) {
         scope.allNodes[index].delete()
     }
v1/src/simulator/src/ux.js (1)

191-216: Debounced changeClockTime handler — verify this context survives the delay.

The arrow function inside setTimeout correctly captures this (the DOM element) from the enclosing jQuery handler. Reading this.value at timeout-fire time returns the latest input value, which is ideal for debounce. This looks correct.

One minor concern: if the input element is removed from the DOM during the debounce window (e.g., user switches circuits), the deferred call will still fire against stale references. Consider guarding:

🛡️ Optional guard
         clockTimeDebounceTimer = setTimeout(() => {
+            if (!document.contains(this)) {
+                clockTimeDebounceTimer = null
+                return
+            }
             checkValidBitWidth()

Comment on lines +87 to 91
* @deprecated This function has been removed as the root cause has been fixed.
* Nodes are now loaded correctly and orphaned nodes are cleaned up properly.
* @category data
*/
function removeBugNodes(scope = globalScope) {
let x = scope.allNodes.length
for (let i = 0; i < x; i++) {
if (
scope.allNodes[i].type !== 2 &&
scope.allNodes[i].parent.objectType === 'CircuitElement'
) {
scope.allNodes[i].delete()
}
if (scope.allNodes.length !== x) {
i = 0
x = scope.allNodes.length
}
}
}

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 | 🟡 Minor

Misleading deprecation comment.

Line 88 states "only intermediate nodes are loaded before modules" but line 103–104 loads all nodes first via data.allNodes.map((x) => loadNode(x, scope)). The comment should accurately describe the current behavior.

📝 Suggested fix
 /**
- * `@deprecated` This function has been removed as the root cause has been fixed.
- * Nodes are now loaded correctly: only intermediate nodes are loaded before modules,
- * and input/output nodes are created as part of their circuit elements.
+ * `@deprecated` removeBugNodes has been removed. Orphaned input/output nodes
+ * are now cleaned up inline in loadScope after module loading.
  * `@category` data
  */
🤖 Prompt for AI Agents
In `@v1/src/simulator/src/data/load.js` around lines 87 - 91, Update the
misleading JSDoc/deprecation comment to reflect current behavior: remove or
replace the phrase "only intermediate nodes are loaded before modules" and state
that all nodes are loaded first (via data.allNodes.map((x) => loadNode(x,
scope))) and orphaned nodes are cleaned up; reference loadNode and
data.allNodes.map to clarify where this loading happens and keep the
category/data deprecation note accurate.

@tachyons
Copy link
Member

Could you add a real world impact of this bug with example ?

- Add detailed JSDoc comments explaining consequences of failed node deletion
- Document memory leaks, simulation errors, and UI glitches
- Include concrete example scenario: deleting gate input node that remains in parent.nodeList
- Explain how this causes simulation failures, console errors, and circuit unresponsiveness
- Clarify the root cause: mismatch between where nodes are added vs where they're removed

Addresses reviewer feedback requesting real-world impact examples
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (3)
src/simulator/src/node.js (3)

957-965: Redundant filter fallback — indexOf always works for identity checks.

Array.prototype.indexOf uses strict equality (===), which is the correct way to find object references in an array. It will never "not work" for this use case. The else branch (line 962-963) is dead code.

♻️ Simplify to just indexOf + splice
         if (this.parent && this.parent.nodeList && Array.isArray(this.parent.nodeList)) {
             const index = this.parent.nodeList.indexOf(this)
             if (index !== -1) {
                 this.parent.nodeList.splice(index, 1)
-            } else {
-                // Fallback: use filter if indexOf doesn't work (shouldn't happen, but safer)
-                this.parent.nodeList = this.parent.nodeList.filter(x => x !== this)
             }
         }

951-975: Double removal from parent.nodeList when called via replace().

The replace() function (line 45) already filters parent.nodeList to remove the node before calling delete(). Then delete() attempts the same removal. This is harmless (indexOf returns -1, splice is skipped), but worth being aware of for clarity.

Additionally, when this.parent === this.parent.scope.root (e.g. intermediate nodes whose parent is root), both the parent-block and root-block operate on the same nodeList array. The second lookup will simply find nothing since the first already removed it — no bug, but the comment "Some edge cases might have nodes in root.nodeList" is misleading for this scenario.


933-943: JSDoc comment is overly verbose for an implementation detail.

This 10-line impact narrative reads more like a commit message or issue description than a code comment. Consider condensing to 2-3 lines explaining what the code does and why, and leave the detailed impact analysis in the PR/issue.

@subhamkumarr
Copy link
Author

Could you add a real world impact of this bug with example ?

@tachyons I've added real-world impact examples in the JSDoc comments for the delete() method. The documentation now includes:

  • Memory leaks: Orphaned nodes remain in nodeList, preventing garbage collection
  • Simulation errors: Deleted nodes still referenced, causing "node not found" errors
  • UI glitches: Deleted nodes may still appear in properties panel or cause crashes
  • Concrete example: When a user deletes a gate's input node but it remains in parent.nodeList, the circuit simulation can fail, produce incorrect results, show browser console errors, become unresponsive, and require a page reload to fix

The changes are in the JSDoc comments at lines 934-943 in src/simulator/src/node.js (and the v1 version). This explains the root cause and the consequences if node deletion fails.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

🐞 Bug: Fix Potential Bug in Node Deletion Logic

2 participants