Skip to content

Replace var with const/let across core/js + scoping fixes#3297

Closed
limad wants to merge 7 commits into
jeedom:developfrom
limad:develop
Closed

Replace var with const/let across core/js + scoping fixes#3297
limad wants to merge 7 commits into
jeedom:developfrom
limad:develop

Conversation

@limad
Copy link
Copy Markdown
Contributor

@limad limad commented Apr 25, 2026

Summary

This PR migrates ~1390 var declarations to const/let across all 33 files in core/js/ and desktop/js/log.js, and fixes 13 bugs identified during the migration via ESLint and runtime testing.

Why

var is function-scoped and hoisted, which leaks variables out of intended blocks and creates implicit window.X globals. const/let are block-scoped and lexically bound, catching reassignment bugs at parse time and avoiding silent global pollution.

Discussion in #3270 raised concerns about using outdated var in new code; this PR addresses the underlying codebase consistently.

Bugs found and fixed during migration

Critical (would crash at runtime):

  • core/js/plugin.template.jsconst eqLogic was reassigned by saveEqLogic() → changed to let
  • core/js/private.class.jsconst value was reassigned by value += '' → changed to let

Scoping regressions from varconst/let (block-scope vs hoisting):

  • core/js/cmd.class.js jeedom.cmd.executeeqLogic was declared inside if (notify) {} but referenced in callbacks at lines 87-172 → hoisted to function scope (would throw ReferenceError: eqLogic is not defined on every command execution from dashboard)
  • core/js/history.class.jsseries was declared in mutually-exclusive if/else blocks but referenced after the block in addSeries() calls → hoisted with let

Global property collisions (var X at top-level was creating window.X):

  • core/js/jeedom.class.js — removed let Highcharts declaration that was shadowing window.Highcharts set by highstock.js (caused TypeError: Highcharts.setOptions is undefined on dashboard load)
  • core/js/private.class.js — renamed const init to _init to avoid SyntaxError: redeclaration of non-configurable global property init (collides with function init() in core.js)

Implicit globals (assignment without declaration — pre-existing):

  • core/js/view.class.jsresult in pre_success and option in handleViewAjax were leaking as globals
  • core/js/core.jsfor (i in _replace) was leaking i as global

Dead code:

  • core/js/private.class.js — removed const param = null that was never used

Multi-term log search (incorporates #3270):

Validation

  • ESLint with no-var, prefer-const, no-const-assign, no-redeclare rules: 0 errors
  • Manual browser testing: dashboard, history, scenario, plugin, log search, view, object pages — no console regressions

Test plan

  • Dashboard loads without ReferenceError/TypeError in console
  • Command execution from dashboard works (was breaking due to eqLogic scoping)
  • History page renders Highcharts charts (was breaking due to Highcharts shadowing)
  • Plugin equipment configuration save works (was breaking due to const eqLogic reassignment)
  • Log search with multi-term and :not() works (Improve log search with multi-term and exclusion support #3270 functionality)
  • Views display correctly (graph zones rely on option variable)

limad and others added 7 commits April 22, 2026 18:17
…tion

- cmd.class.js: hoist eqLogic out of `if (notify)` block (was breaking
  callbacks at lines 87-172 with ReferenceError)
- history.class.js: hoist series out of mutually-exclusive if/else blocks
  (referenced after the block in addSeries calls and config object)
- core.js: declare loop variable `i` in `for (i in _replace)` (was leaking
  as implicit global)
- view.class.js: declare `result` and `option` (were leaking as implicit
  globals in pre_success and handleViewAjax)
- private.class.js: remove dead `const param = null` declaration
- desktop/js/log.js: apply PR jeedom#3270 multi-term search refactor with
  proper const/let usage instead of var

Found via ESLint (no-var, prefer-const, no-const-assign) plus targeted
audit for var→let/const block-scoping regressions.
Resolved conflict in docs/release-notes.md by taking upstream version
(file is auto-generated by .github/workflows/draft-release-notes.yml).
@Salvialf
Copy link
Copy Markdown
Contributor

Salvialf commented Apr 25, 2026

Hi,

I’m not against revisiting JavaScript variable declarations, but in its current form this PR is almost impossible to review properly without re-reading every single file in full. const, let and var have different semantics and each of them has its place depending on the context.

A large, cross-cutting change that touches ~1400 declarations across 30+ files makes it very hard to be confident there are no subtle regressions, especially around scoping and hoisting. Even with the fixes you listed, it’s not realistic to validate all behavior changes just from the diff.

Would it be possible to split this into smaller, focused PRs (for example per module or starting from the concrete bugs you already identified), so that each change set can be reviewed and tested more thoroughly?

@kwizer15
Copy link
Copy Markdown
Contributor

kwizer15 commented Apr 26, 2026

I agree with @Salvialf
Also, it would be interesting to add a GitHub Action that runs ESLint with the rules you’ve defined.
Is it possible to add a baseline system similar to what was done with lint? That would help prevent regressions.

@limad
Copy link
Copy Markdown
Contributor Author

limad commented Apr 28, 2026

Thanks @Salvialf and @kwizer15 for the feedback — both points are entirely fair.

Context: this work is part of a code optimization effort that has been discussed on and off for a long time (the var vs const/let topic came up notably in #3270 and earlier). The initial goal was not bug fixing — no concrete bugs were known beforehand. The bulk of the time was spent validating the outcome and checking for regressions rather than performing the migration itself, which is largely mechanical.

The 13 bugs documented in the description were discovered along the way — either via ESLint (no-const-assign on variables that were actually being reassigned) or during the runtime validation phase (hoisting regressions where a var declared inside an if/for/try block became block-scoped after migration to const/let and broke references in callbacks).

Audit: the desktop UI pages have been audited (in part with the help of AI tooling to systematically walk through the critical paths: dashboard, history, scenarios, plugins, views, logs, configuration modals). I'm aware that a hidden regression on a rarely-used path cannot be entirely ruled out — which is precisely why @kwizer15's suggestion on automating ESLint in CI is valuable.

Action: splitting as suggested.

  • PR A — bug fixes only (6 files, ~25 lines) — quick to review and merge
  • PR B — ESLint workflow + baseline — to tool the rest of the work
  • PR C–F — the var → const/let migration split into 4 batches grouped by functional domain (utilities / equipment & commands / UI rendering / admin & system)

Closing this PR in favor of the splits. Thanks for the feedback — it genuinely improves the quality of the contribution.

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.

3 participants