Skip to content

Feature: Depedency detection#1392

Closed
EdrilanBerisha wants to merge 4 commits into
UI5:mainfrom
EdrilanBerisha:main
Closed

Feature: Depedency detection#1392
EdrilanBerisha wants to merge 4 commits into
UI5:mainfrom
EdrilanBerisha:main

Conversation

@EdrilanBerisha
Copy link
Copy Markdown

@EdrilanBerisha EdrilanBerisha commented May 21, 2026

The JSModuleAnalyzer in packages/builder/lib/lbt/analyzer/JSModuleAnalyzer.js now detects module dependencies when known UI5 APIs are called through local alias names, not just their canonical names. Three patterns are supported:

  1. Factory function parameter aliasing jquery.sap.global:

    sap.ui.define(["jquery.sap.global"], function(jq) { jq.sap.require("my.module"); });
  2. Factory function parameter aliasing sap/ui/core/Core:

    sap.ui.define(["sap/ui/core/Core"], function(ui) { ui.require(["my/dep"]); ui.requireSync("other/dep"); });
  3. Top-level variable assignments:

    var jq = jQuery;  // or var jq = $; or var ui = sap.ui;
    jq.sap.require("my.module");

Tests: 27 new unit tests were written in JSModuleAnalyzer_aliasDetection.js covering all alias patterns, conditional branches, position correctness guards, regression coverage for canonical calls, and fixture-file based tests. All 27 new tests + all 54 existing tests pass.

Feature was requested: UI5/cli#512

The condition !projectCustomMiddleware.length === 0 was always false
due to JavaScript operator precedence: the ! unary operator converts
length to a boolean first (yielding true for an empty array), and
true === 0 is always false. As a result the early-return guard
never fired, so addCustomMiddleware() always iterated the array even
when it was empty.

Fix by using the correct expression projectCustomMiddleware.length === 0.

Add two regression tests that explicitly cover:
- an empty custom middleware array causes an early return (no calls to
  addMiddleware or getExtension)
- a non-empty custom middleware array is still processed correctly

Fixes UI5#647
…nalyzer

Implements feature request UI5#512.

Previously, the JSModuleAnalyzer could only detect dependencies when
well-known UI5 APIs (jQuery.sap.require, sap.ui.require, etc.) were
called by their canonical names. If a factory function parameter or a
top-level variable held a reference to the same object under a different
local name, the calls through that alias were silently ignored.

This commit adds alias tracking to the analyzer. Three patterns are now
supported:

1. Factory function parameter aliasing jquery.sap.global
   sap.ui.define(["jquery.sap.global"], function(jq) {
     jq.sap.require("my.module");        // detected
     jq.sap.declare("my.module");        // detected
     jq.sap.registerPreloadedModules({}); // detected
   });

2. Factory function parameter aliasing sap/ui/core/Core
   sap.ui.define(["sap/ui/core/Core"], function(ui) {
     ui.require(["my/dep"]);             // detected
     ui.requireSync("other/dep");        // detected
   });

3. Top-level variable assignments
   var jq = jQuery;                      // or var jq = $;
   jq.sap.require("my.module");          // detected

   var ui = sap.ui;
   ui.require(["my/dep"]);               // detected

Implementation notes:
- A Map (aliasMap) is populated before visiting the factory body.
- registerFactoryParamAliases() inspects the dependency array and maps
  each parameter name to either "jquery" or "sap.ui" based on the known
  module IDs (jquery.sap.global, sap/ui/core/Core).
- registerVariableDeclaratorAlias() handles top-level var assignments.
- handleAliasCall() is called for every CallExpression as a fallback
  check; it delegates to the existing onJQuerySapRequire / onDeclare /
  onSapUiRequireSync / analyzeDependencyArray handlers, so all the same
  logic (conditional detection, format setting, etc.) applies.
- The isDeclared alias pattern inside if-statements is also handled.
- Alias map is per-analyze() call; no state leaks between files.

Tests added (27 new tests in JSModuleAnalyzer_aliasDetection.js):
- Factory param jQuery alias: require detection, multi-require, position
  correctness, unrelated param guard, no-dep-array guard
- Factory param sap.ui alias: require, requireSync, callback body visit,
  position correctness
- Top-level var jq = jQuery: require, declare, multiple, $ sign
- Top-level var ui = sap.ui: require, requireSync
- Mixed aliases in one module
- Conditional branch detection for alias calls
- Regression tests confirming canonical calls still work

Also added 5 fixture JS files in test/fixtures/lbt/modules/.
@flovogt flovogt requested review from RandomByte and codeworrior May 22, 2026 07:43
@flovogt
Copy link
Copy Markdown
Member

flovogt commented May 22, 2026

Thanks a lot for your contribution. We will discuss your enhancement request in the team and give an update here.

@RandomByte
Copy link
Copy Markdown
Member

Thank you for looking into this and contributing.

We had a closer look and have a few concerns before we can move forward. Issue #512 describes one specific pattern: a factory parameter aliasing jquery.sap.global. The PR goes considerably beyond that and adds three further patterns that weren't requested — and one of them is unfortunately incorrect: sap/ui/core/Core exports a Core instance, not the sap.ui namespace, so core.require(...) is not equivalent to sap.ui.require(...). Treating it as such would produce false positives on existing UI5 code that calls methods on the Core instance.

The other concern is scope. aliasMap is a single map for the whole analyze() call, populated for every VariableDeclarator regardless of nesting and never cleared on scope exit. That means a var jq = jQuery in a nested closure leaks into the rest of the file, and any later jq parameter shadowing the alias gets misinterpreted. The analyzer already imports escope, but here a simpler approach should be sufficient: scope the alias map to the factory body of the sap.ui.define / define call that introduced it, so its lifetime matches the factory.

For a focused change that addresses the issue, I'd suggest:

  • Limit the scope to the jquery.sap.global factory parameter case from the issue. If the var-assignment patterns turn out to be needed in practice, we can follow up separately.
  • Inline the parameter→alias mapping into the existing Syntax.CallExpression branch where sap.ui.define / define is already handled, so it lives only for that factory body.
  • Reuse fromUI5LegacyName / fromRequireJSName (already imported at the top of the file) instead of the new ad-hoc normalisation — those are the canonical helpers and will stay consistent with the rest of the analyzer.
  • Drop the unused JQUERY_SAP_GLOBAL_MODULE_IDS constant and the unreachable SAP_UI_CORE_MODULE_ID comparison.
  • Keep the tests that cover the jQuery factory-param case and add a shadowing negative test (e.g. an inner function with a parameter of the same name) to pin down the scope behaviour.

Per review feedback on PR UI5#1392 from @RandomByte:

- Remove the sap/ui/core/Core factory parameter alias (sap/ui/core/Core
  exports a Core instance, not sap.ui — treating it as sap.ui.require
  would produce false positives on existing UI5 code).
- Remove the top-level variable alias patterns (var jq = jQuery;
  var ui = sap.ui) — these were out of scope for issue UI5#512 and
  introduced leaking alias state across the whole file.
- Remove the global aliasMap. The new implementation uses a per-factory
  Set (jQueryAliases) built right before visiting each factory body and
  passed as a parameter through the visitor recursion. Its lifetime
  exactly matches the factory body; aliases from one define call never
  bleed into sibling define calls.
- Inline the parameter→alias mapping using fromUI5LegacyName (the
  canonical helper already imported at the top of the file) and
  MODULE__JQUERY_SAP_GLOBAL for the comparison.
- Remove the unused JQUERY_SAP_GLOBAL_MODULE_IDS constant and the
  incorrect/unreachable SAP_UI_CORE_MODULE_ID comparison.
- Remove the helper functions isAliasMethodCall / registerFactoryParamAliases /
  registerVariableDeclaratorAlias / handleAliasCall which are no longer
  needed.
- Inline the alias detection directly in the existing
  Syntax.CallExpression branch that handles sap.ui.define / define.
- Drop the fixture files for removed patterns; keep only
  alias_jquery_factory_param_require.js.
- Update tests: keep tests covering the jquery.sap.global factory param
  case, add a scope-bleed negative test (sibling define) and document
  the scoping behaviour in the shadowing test comment.
@RandomByte
Copy link
Copy Markdown
Member

Even after the review, this still looks like slop to me so I'm closing this PR for now.

I have doubts that you are personally interested in resolving #512 (a five year old issue with no activity) and/or learning about the inner workings of this project. It rather feels like you are using a coding agent to try and make contributions to SAP OSS projects for your portfolio. We take contributions seriously and we generally review them with a human in the loop, so please be more considerate of our time.

Please reach out to me internally if I'm misjudging you and I will update this comment.

Regarding #512: Please let us know if you are actually affected by this bug so we can prioritize a fix (and also understand the specific scope to resolve your case). In that case however, I think it would be more efficient for us to prompt a solution and iterate over it ourselves, rather than going through you. Unless you are actually interested in learning about this project.

@RandomByte RandomByte closed this May 22, 2026
@RandomByte RandomByte added the invalid This doesn't seem right label May 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

invalid This doesn't seem right

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants