Skip to content

Conversation

@sensei-hacker
Copy link
Member

@sensei-hacker sensei-hacker commented Jan 28, 2026

User description

Summary

Fixes a bug in the JavaScript Programming decompiler where spaces between words were being replaced with custom variable names, resulting in corrupted output like "constmin" instead of "const min" and "INAVminJavaScript" instead of "INAV JavaScript".

This PR depends on #2539 and should be merged after 2539

Root Cause

In decompiler.js at line 293, the applyCustomVariableNames() function was storing entire objects from hoistedActivatorVars instead of extracting the varName string property:

// Before (buggy):
for (const [lcIndex, generatedName] of this.hoistingManager.hoistedActivatorVars.entries()) {
  lcIndexToGeneratedName.set(lcIndex, generatedName); // Stores whole object!
}

When the object was used in a template literal to build a regex pattern, it converted to the string "[object Object]", which created a regex character class [object Object] matching any character from the set {o,b,j,e,c,t,space,O}. This caused the pattern \b[object Object]\b to match spaces between word boundaries.

Changes

Modified inav-configurator/js/transpiler/transpiler/decompiler.js lines 293-294:

// After (fixed):
for (const [lcIndex, entry] of this.hoistingManager.hoistedActivatorVars.entries()) {
  lcIndexToGeneratedName.set(lcIndex, entry.varName); // Extract string property
}

This ensures the regex replacement uses the actual variable name string instead of the [object Object] character class.

Testing

✅ Tested with problematic logic conditions via browser console
✅ Verified no "constmin" corruption
✅ Verified no "AccessminAPI" corruption
✅ Verified proper spacing in comments: "// INAV JavaScript Programming"
✅ Verified proper spacing in code: "const min = ..."
✅ All test cases passed

Tested using the running configurator instance by:

  1. Importing the Decompiler module
  2. Decompiling the exact logic conditions that triggered the bug
  3. Verifying output has proper spacing throughout

Code Review

Reviewed with inav-code-review agent - APPROVED with no critical or important issues found.

The fix:

  • Correctly extracts the varName string property from entry objects
  • Makes variable naming self-documenting (entry instead of generatedName)
  • Follows single responsibility principle
  • No edge case concerns (null-safe due to Map iteration)

Related

Addresses user-reported issue where decompiled code showed corrupted spacing.


PR Type

Enhancement, Bug fix


Description

  • Implement real-time active Logic Condition highlighting in Monaco editor

    • Status polling every 500ms with gutter decorations (green checkmarks for TRUE, gray circles for FALSE)
    • LC-to-line mapping tracks which conditions appear on which code lines
    • Handles compound conditions, hoisted variables, and sticky/timer patterns
  • Fix bug in decompiler where spaces were replaced with variable names

    • Extract varName string property instead of storing entire object
    • Prevents regex pattern corruption from [object Object] character class
  • Add line offset tracking for accurate source-to-editor line number mapping

    • Codegen tracks current source line during statement processing
    • Decompiler finalizes mapping after boilerplate code generation

Diagram Walkthrough

flowchart LR
  A["Logic Conditions<br/>Status"] -->|"500ms polling"| B["updateActiveHighlighting()"]
  B -->|"categorize by status"| C["categorizeLCsByStatus()"]
  C -->|"map to lines"| D["mapLCsToLines()"]
  D -->|"create decorations"| E["createMonacoDecorations()"]
  E -->|"apply to editor"| F["Monaco Gutter<br/>Decorations"]
  G["Transpiler/Decompiler"] -->|"track LC indices"| H["lcToLineMapping"]
  H -->|"enable highlighting"| F
  I["Decompiler Bug Fix"] -->|"extract varName"| J["Correct Regex<br/>Pattern"]
Loading

File Walkthrough

Relevant files
Configuration changes
monaco_loader.js
Enable Monaco gutter margin for decorations                           

js/transpiler/editor/monaco_loader.js

  • Enable gutter margin in Monaco editor configuration with glyphMargin:
    true
  • Allows gutter decorations for active LC highlighting to be displayed
+1/-0     
New feature
lc_highlighting.js
New module for Logic Condition highlighting utilities       

js/transpiler/lc_highlighting.js

  • New module providing LC highlighting utilities
  • categorizeLCsByStatus() separates enabled LCs into TRUE/FALSE arrays
  • mapLCsToLines() maps LC indices to editor lines with combined status
    (true/false/mixed)
  • createMonacoDecorations() generates gutter marker decorations with
    hover messages
  • applyDecorations() and clearDecorations() manage decoration lifecycle
+138/-0 
javascript_programming.js
Implement active LC highlighting with status polling         

tabs/javascript_programming.js

  • Add lcToLineMapping, activeDecorations, and statusChainer properties
    for highlighting state
  • Import interval and LCHighlighting modules
  • Store Monaco reference for use in highlighting functions
  • Add setupActiveHighlighting() to create 500ms polling interval for LC
    status updates
  • Add updateActiveHighlighting() to categorize LCs, map to lines, and
    apply decorations
  • Add clearActiveHighlighting() to remove all gutter decorations
  • Fix isDirty race condition by using setTimeout() after setValue()
    calls
  • Clear stale mapping and decorations when loading logic conditions
  • Stop polling and cleanup decorations in cleanup() method
+147/-4 
Enhancement
codegen.js
Add LC-to-line mapping tracking in code generation             

js/transpiler/transpiler/codegen.js

  • Add lcToLineMapping object to track LC index to source line mapping
  • Add currentSourceLine and lineOffset properties for line tracking
  • Track source line in generateStatement() using AST location info
  • Record LC-to-line mapping in pushLogicCommand() when LC is created
  • Subtract lineOffset from Acorn line numbers to match Monaco editor
    line numbers
+45/-22 
index.js
Pass line offset and mapping to transpiler result               

js/transpiler/transpiler/index.js

  • Pass lineOffset from transpiler to codegen for accurate line number
    tracking
  • Return lcToLineMapping from transpile result for highlighting support
+3/-1     
javascript_programming.html
Add CSS styling for active LC gutter markers                         

tabs/javascript_programming.html

  • Add .lc-active-true CSS class with green checkmark SVG icon for TRUE
    conditions
  • Add .lc-active-false CSS class with gray hollow circle SVG icon for
    FALSE conditions
  • Add Monaco gutter margin background styling and cursor styling
  • Gutter markers are 16x16px with proper opacity and colors
+28/-0   
Bug fix
decompiler.js
Fix space replacement bug and add LC-to-line mapping         

js/transpiler/transpiler/decompiler.js

  • Fix bug: extract entry.varName instead of storing entire object in
    lcIndexToGeneratedName map
  • Add lcToLineMapping and _tempLcLines properties for tracking LC line
    positions
  • Track if-statement lines during decompilation in decompileTree()
  • Add finalizeLcLineMapping() method with 5-pass algorithm to map LCs to
    final code lines
  • Handle hoisted variables, sticky/timer patterns, activator
    relationships, and compound conditions
  • Return lcToLineMapping in decompile result
+132/-3 

Augment decompiler to track which Logic Conditions map to which lines
in generated JavaScript code. This enables real-time highlighting of
active conditions in the JavaScript Programming tab.

Key features:
- 3-pass mapping algorithm handles simple, compound, and nested conditions
- Compound conditions (a && b) correctly map all sub-LCs to same line
- Activator chains propagate line numbers to child LCs
- Hoisted variables and sticky/timer patterns tracked
- Returns lcToLineMapping in decompile() result

Part of Feature 1: Active LC Highlighting (Phase 1/5)
Implement real-time status polling and gutter decoration updates in the
JavaScript Programming tab to show which Logic Conditions are currently
active/true.

Key features:
- Status polling every 100ms using MSPChainer
- updateActiveHighlighting() filters true LCs and applies gutter markers
- clearActiveHighlighting() when code is dirty (unsaved changes)
- Proper cleanup on tab switch/disconnect
- isDirty check prevents highlighting stale code

Part of Feature 1: Active LC Highlighting (Phase 2/5)
Implement CSS and Monaco editor configuration for green checkmark gutter
markers that indicate active/true Logic Conditions.

Key changes:
- Add .lc-active-true CSS class with SVG green checkmark icon
- Add Monaco gutter margin background styling
- Enable glyphMargin: true in Monaco editor options
- Set up proper cursor and sizing for gutter decorations

Part of Feature 1: Active LC Highlighting (Phase 3/5)
Fix 'Cannot read properties of null' error in updateActiveHighlighting()
by adding proper null checks for FC.LOGIC_CONDITIONS_STATUS and
FC.LOGIC_CONDITIONS before accessing .get().

This prevents errors during tab initialization when FC data is still loading.
The onChange handler was firing after setValue() during load, causing
isDirty to be set to true even after we cleared it. This prevented the
highlighting from ever appearing because updateActiveHighlighting()
returns early when isDirty is true.

Fixed by using setTimeout() to clear isDirty after the setValue() change
event has been processed.
Previous approach tried to find LCs by parsing the generated code for
/* LC X */ comments, but normal if-statements don't have these comments.

New approach:
- Track LC index and line content during code generation
- After adding boilerplate, search for the tracked lines in final code
- Map LC index to actual line numbers in final output

This ensures all if-statements and their associated LCs get mapped
correctly for the active highlighting feature.
Track what's being searched for and what's being found to diagnose
why the LC-to-line mapping is empty.
This will help us diagnose why the green checkmarks aren't appearing
by logging:
- When the function is called
- If isDirty is blocking it
- What the LC-to-line mapping is
- If FC data is available
- Which LCs are TRUE
- What lines should be highlighted
- If decorations are created
FC.LOGIC_CONDITIONS_STATUS.get() requires a condition index parameter
and returns a single value. We need getAll() to get the entire status array.

This was causing 'FC data is null' errors and preventing any highlighting
from appearing.
This completes the active LC highlighting feature with two major improvements:

1. FALSE condition indicators: Gray hollow circles (○) display when conditions
   evaluate to FALSE, complementing the existing green checkmarks for TRUE
   conditions. Mixed states (TRUE and FALSE on same line) show green checkmark.

2. Transpiler-side line tracking: LC-to-line mappings are now generated during
   transpilation, providing immediate visual feedback after "Transpile" or
   "Save to FC" without requiring "Load from FC" roundtrip. Correctly adjusts
   for auto-added import statement offset.

Technical changes:
- Add lineOffset tracking in codegen to account for prepended import lines
- Store currentSourceLine context during statement generation
- Return lcToLineMapping in transpiler result
- Update tab to use transpiler mapping immediately after transpile/save
- Change polling interval from 100ms to 500ms to reduce MSP load (2Hz vs 10Hz)
- Reorder checks: verify FC data availability before isDirty state
- Clean up excessive debug logging for production readiness

Testing:
- Verified circles appear on correct lines after transpile
- Tested TRUE/FALSE/MIXED states display properly
- Confirmed decompiler mapping replaces transpiler mapping on load
- Reviewed with inav-code-review agent - all critical issues resolved
Fixes all 6 medium-priority issues identified by qodo-merge bot:
1. Clear stale decorations when loading code from FC
2. Clear mapping/decorations when loading default code
3. Add in-flight guard to prevent overlapping MSP polling requests
4. Remove duplicate intervals before adding new one
5. Improve type safety with Array.isArray() checks for MSP data

Code organization improvements:
- Extract highlighting logic to new module js/transpiler/lc_highlighting.js
- Reduce tab file from 928 to 893 lines (-35 lines)
- Create 5 testable, pure functions: categorizeLCsByStatus(),
  mapLCsToLines(), createMonacoDecorations(), applyDecorations(),
  clearDecorations()
- Better separation of concerns (tab orchestrates, module implements)
- Improved code maintainability and testability
**Problem:**
When decompiling logic conditions with activator hoisting and a stored
variable map, all spaces between words were being replaced with custom
variable names (e.g., "const min" became "constmin", comments like
"INAV JavaScript Programming" became "INAVminJavaScriptminProgramming").

**Root Cause:**
In decompiler.js applyCustomVariableNames() at line 293, the code was
storing entire objects from hoistedActivatorVars instead of extracting
the varName string:

  const entry = { varName: 'cond1', scopeLcIndex: -1 }

When this object was used in a template literal to build a regex pattern:
  `\\b${entry}\\b` → `\\b[object Object]\\b`

In regex, `[object Object]` is a CHARACTER CLASS that matches any single
character from the set: {o,b,j,e,c,t,space,O}. This caused the regex
pattern `\\b[object Object]\\b` to match spaces between word boundaries,
replacing them with the custom variable name.

**Fix:**
Changed line 293-294 to extract the .varName property:
  - Before: lcIndexToGeneratedName.set(lcIndex, generatedName);
  - After: lcIndexToGeneratedName.set(lcIndex, entry.varName);

This ensures the regex replacement uses the actual variable name string
instead of "[object Object]" character class.

**Files Changed:**
- js/transpiler/transpiler/decompiler.js

**Testing:**
Verified with test cases showing the fix prevents space replacement in
both code and comments.
@qodo-code-review
Copy link
Contributor

ⓘ Your approaching your monthly quota for Qodo. Upgrade your plan

PR Compliance Guide 🔍

All compliance sections have been disabled in the configurations.

@sensei-hacker sensei-hacker added this to the 9.1 milestone Jan 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant