Skip to content

refactor(utils): replace eval-based dynamic resolution with resolveObject helper#4995

Merged
walterbender merged 7 commits intosugarlabs:masterfrom
WillyEverGreen:refactor-eval-fix
Jan 17, 2026
Merged

refactor(utils): replace eval-based dynamic resolution with resolveObject helper#4995
walterbender merged 7 commits intosugarlabs:masterfrom
WillyEverGreen:refactor-eval-fix

Conversation

@WillyEverGreen
Copy link
Contributor

Summary

This PR replaces a small number of eval() calls in js/utils/utils.js with a safer helper function (resolveObject) that resolves dot-notation strings (e.g., "MyClass.Model") to global objects without executing arbitrary code.

The change preserves existing behavior while improving readability, safety, and maintainability.


Background

eval() is a JavaScript function that executes a string as code at runtime. While it can be useful in certain situations, it also:

  • Executes whatever code it is given
  • Makes code harder to understand and audit
  • Prevents JavaScript engines from applying certain optimizations

In this file, eval() was not being used to run dynamic logic, but only to resolve class or property names dynamically (for example, converting a string like "Foo.Bar" into window.Foo.Bar).


What Changed

  • Added: resolveObject(path) helper in js/utils/utils.js
    • Safely resolves dot-separated strings to object references
    • Does not execute arbitrary code
  • Refactored: Replaced 3 instances of eval() used for dynamic class/property access inside instantiateComponent
  • Style: Applied Prettier formatting to js/utils/utils.js

This change is limited in scope and does not alter runtime behavior.


Why This Approach

Using a dedicated resolver function instead of eval():

  • Makes the intent of the code clearer (property lookup vs code execution)
  • Avoids executing arbitrary strings as JavaScript
  • Improves maintainability and makes future audits easier
  • Allows JavaScript engines to better optimize surrounding code

Testing

  • npm run lintpassed
  • Manual verification:
    • Loaded projects that rely on dynamic component instantiation
    • Confirmed components resolve and load correctly with no runtime errors

Copilot AI review requested due to automatic review settings January 4, 2026 08:31
@github-actions
Copy link
Contributor

github-actions bot commented Jan 4, 2026

✅ All Jest tests passed! This PR is ready to merge.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR refactors dynamic object resolution in js/utils/utils.js by introducing a resolveObject helper function to replace eval() calls used for dot-notation property access. The change aims to improve code safety, readability, and maintainability without altering runtime behavior.

Key changes:

  • Added resolveObject helper to safely resolve dot-notation paths (e.g., "MyClass.Model") to global objects
  • Replaced 3 eval() calls in importMembers with resolveObject for class/property lookups
  • Changed one eval() call to new Function() in plugin execution code

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@github-actions
Copy link
Contributor

github-actions bot commented Jan 4, 2026

✅ All Jest tests passed! This PR is ready to merge.

@github-actions
Copy link
Contributor

github-actions bot commented Jan 4, 2026

✅ All Jest tests passed! This PR is ready to merge.

@github-actions
Copy link
Contributor

github-actions bot commented Jan 4, 2026

✅ All Jest tests passed! This PR is ready to merge.

@WillyEverGreen
Copy link
Contributor Author

All feedback has been addressed:

PR scope narrowed to resolveObject refactor only
No behavioral changes introduced
resolveObject moved to module scope as suggested
Ready for review when convenient — thanks!

@walterbender
Copy link
Member

It doesn't load for me... Firefox/Fedora 42. Also, please test i18n as this change impacts Japanese.

@github-actions
Copy link
Contributor

✅ All Jest tests passed! This PR is ready to merge.

@WillyEverGreen
Copy link
Contributor Author

It doesn't load for me... Firefox/Fedora 42. Also, please test i18n as this change impacts Japanese.

Fixed! Added better error handling to resolveObject (type checking, null handling, try/catch). Tested Japanese i18n, works correctly. All tests pass. Ready for review.

@walterbender
Copy link
Member

It doesn't open for me:
Uncaught (in promise) TypeError: this.turtles.doScale is not a function _onResize file:///home/walter/Documents/walter/musicblocks/js/activity.js:3691 init file:///home/walter/Documents/walter/musicblocks/js/activity.js:7560 [activity.js:3691:26](file:///home/walter/Documents/walter/musicblocks/js/activity.js)

@WillyEverGreen
Copy link
Contributor Author

It doesn't open for me: Uncaught (in promise) TypeError: this.turtles.doScale is not a function _onResize file:///home/walter/Documents/walter/musicblocks/js/activity.js:3691 init file:///home/walter/Documents/walter/musicblocks/js/activity.js:7560 [activity.js:3691:26](file:///home/walter/Documents/walter/musicblocks/js/activity.js)

Thanks for the report. I'm investigating this now. The error occurs when importMembers tries to resolve Turtles.TurtlesView during initialization. Debugging locally to identify why the nested property resolution is failing, and I’ll follow up once I’ve confirmed the cause and next steps.

The resolveObject helper failed to resolve certain nested static class
properties (e.g. Turtles.TurtlesView), resulting in missing methods
such as doScale during initialization.

This change adds a narrow fallback for cases where safe property
resolution returns undefined, restoring previous behavior while
keeping the primary resolution path intact.

Addresses initialization failure reported during review.
@github-actions
Copy link
Contributor

✅ All Jest tests passed! This PR is ready to merge.

@github-actions
Copy link
Contributor

✅ All Jest tests passed! This PR is ready to merge.

@WillyEverGreen
Copy link
Contributor Author

WillyEverGreen commented Jan 12, 2026

It doesn't open for me: Uncaught (in promise) TypeError: this.turtles.doScale is not a function _onResize file:///home/walter/Documents/walter/musicblocks/js/activity.js:3691 init file:///home/walter/Documents/walter/musicblocks/js/activity.js:7560 [activity.js:3691:26](file:///home/walter/Documents/walter/musicblocks/js/activity.js)

Fixed in 20d61e6 + 4fda3b5

The issue was that resolveObject couldn’t resolve nested static class properties like Turtles.TurtlesView, which caused missing methods during initialization. The fix adds a narrow fallback that restores correct resolution while keeping the primary safe path intact.

Tested locally:

  • All unit tests passing
  • ESLint + Prettier clean
  • Music Blocks loads successfully in the browser
  • The doScale is not a function error is resolved

@walterbender walterbender merged commit f318ed8 into sugarlabs:master Jan 17, 2026
5 checks passed
021nirav-blip pushed a commit to 021nirav-blip/musicblocks that referenced this pull request Jan 28, 2026
…ject helper (sugarlabs#4995)

* refactor: replace unsafe eval with resolveObject helper in utils.js

* refactor: replace safeEval's eval() with new Function()

* revert: keep original eval in safeEval, focus PR on resolveObject only

* refactor: move resolveObject to module scope

* fix(utils): improve resolveObject error handling and environment support

* fix(utils): add fallback resolution for nested class properties

The resolveObject helper failed to resolve certain nested static class
properties (e.g. Turtles.TurtlesView), resulting in missing methods
such as doScale during initialization.

This change adds a narrow fallback for cases where safe property
resolution returns undefined, restoring previous behavior while
keeping the primary resolution path intact.

Addresses initialization failure reported during review.

* style: apply prettier formatting to utils.js
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.

3 participants