Fix JavaScript Global Access (no-globals)
Fixes no-globals errors in JavaScript files that the UI5 linter detects but cannot auto-fix. Run npx @ui5/linter --details to get replacement suggestions and documentation links.
Key Rules — Read Before Applying Any Fix
-
jQuery/$ globals — preserve jQuery API calls: When fixing jQuery/$ globals, ONLY add the
sap/ui/thirdparty/jquerydependency and replace$withjQuery. Do NOT replace standard jQuery API calls (jQuery.each,jQuery.extend,jQuery.proxy,jQuery.isEmptyObject, etc.) with native JavaScript equivalents. These are standard jQuery methods, not deprecated SAP APIs. -
Case 9/10 — fix ALL globals in a single pass: When converting a file from
jQuery.sap.declare/requiretosap.ui.define(Case 9 or 10), you MUST also fix ALL other global-access patterns inside the file body in the same pass. There is no second pass — everything must be handled at once. Read the "Apply ALL Applicable Cases in a Single Pass" section below. -
Dead code — delete, don't import: If a global assignment stores a value that is never read anywhere else in the file (e.g.,
this.BarColor = sap.ui.core.BarColorwherethis.BarColornever appears again), delete the entire statement. Do NOT add an import for it. -
No intermediate forms for byId in controllers:
sap.ui.getCore().byId("prefix--id")orjQuery("#prefix--id").control(0)inside a controller →this.byId("id")directly. Never leave it asElement.getElementById("prefix--id"). After replacing, remove unusedElementorjQueryimports. -
merge, not deepExtend:
jQuery.sap.extend(true, ...)→merge()fromsap/base/util/merge. The modulesap/base/util/deepExtenddoes NOT exist.
Fix Strategies by Case
1. Assignments to Global Namespaces
Problem: Code creates custom namespaces on the global sap object.
1b. Global Namespace Assignment Inside sap.ui.define
Problem: File is already in sap.ui.define but still assigns to a global namespace and returns the global reference (leftover from jQuery.sap.declare removal).
Not reported by linter — search manually: grep -rl "your\.project\.namespace\." webapp/ --include="*.js"
Key rules: Extract short name from namespace end. Use var ShortName (scoping is essential). Replace all references to the full namespace within the file.
1c. Global Namespace Read-Only Reference Inside sap.ui.define
Problem: File reads from a global namespace via variable assignment instead of importing the module as a dependency.
Not reported by linter — search: grep -rn "var .* = your\.project\.namespace\." webapp/ --include="*.js"
Key rules:
- Convert dot-notation to slash-notation:
com.example.app.utils.Helper→"com/example/app/utils/Helper" - Add to dependency array at the beginning (see Notes), add corresponding parameter
- Remove the
var X = global.namespace.X;line - If multiple global reads exist, add all as dependencies in one pass
- Verify parameter name matches the module's short name
- Atomicity: Every global→local replacement MUST be paired with a
sap.ui.definedependency. Cycles introduced here are resolved later byfix-cyclic-deps - Post-fix validation: Grep for every introduced variable name — confirm it resolves to a parameter, var/let/const, or
sap.ui.requirecall
Before replacing, read the target module's return statement:
Side-effect modules: If the target ends with }); without a return, open it, replace the global namespace assignment with a local var, and add return varName;. Then import normally in the consuming module.
2. sap.ui.getCore() Calls
Problem: sap.ui.getCore() is deprecated; its methods have moved to dedicated modules.
Note: Core.ready() is for boot-phase init scripts. Inside controllers, UI5 is already initialized — don't use it there.
Key replacements (full table in references/core-api-replacements.md):
Use the UI5 MCP Server's get_api_reference tool for additional Core method replacements.
3. sap.ui.core.Core Direct Access
Add sap/ui/core/Core to the dependency array and remove the global access:
4. jQuery/$ Global Access
IMPORTANT: The fix is adding the import, NOT replacing jQuery API calls. jQuery.sap.* (with .sap.) = deprecated, must be replaced (Case 4b). jQuery.* (without .sap.) or jQuery(...) = standard jQuery, keep as-is.
NEVER replace these standard jQuery methods — they are not deprecated in UI5: jQuery.each, jQuery.extend, jQuery.proxy, jQuery.isEmptyObject, jQuery.isArray, jQuery.inArray, jQuery.grep, jQuery.map, jQuery.type, jQuery.trim.
4a. jQuery DOM Lookup for UI5 Controls → this.byId()
Problem: jQuery("#prefix--id").control(0) or Element.closestTo() to get a UI5 control inside a controller.
Detection patterns — all collapse to this.byId("<local-id>"):
jQuery("#<anything>--<id>").control(0)Element.closestTo(jQuery("#<anything>--<id>")[0])sap.ui.getCore().byId("<full-id>")where ID contains view prefixElement.getElementById("<full-id>")where ID contains--
The local ID is the part after the last --. After replacing, remove unused jQuery/Element imports.
4b. jQuery.sap.* Utility Access
Problem: jQuery.sap.* calls are deprecated UI5 utilities with dedicated replacement modules.
Run npx @ui5/linter --details for suggested replacements. Full table in references/core-api-replacements.md.
jQuery.sap.extend decision:
- Deep copy (
trueas first arg) →sap/base/util/merge→merge({}, obj1, obj2) - Flat objects (single-level properties) →
Object.assign({}, obj1, obj2)(no import needed) - NEVER convert to
jQuery.extend(...)(introduces unnecessary dependency) - NEVER use
sap/base/util/deepExtend(does NOT exist)
5. Conditional/Probing Global Access
Problem: Code checks if a global exists: if (sap.ui.fl && sap.ui.fl.Utils) { ... }
Fix: For always-available modules, add as sap.ui.define dependency. For truly optional modules, use synchronous sap.ui.require:
For lazy loading, use async: sap.ui.require(["module/path"], function(Mod) { ... }).
6. Custom Namespace Definitions
Same pattern as Case 1 but for non-SAP namespaces (window.mycompany.myapp = {...}). Convert to sap.ui.define module returning the object. Consumers import via dependency.
7. Binding Type Strings Without Import
8. Delete Expressions
delete sap.ui.core.someTempProperty — usually a code smell. Remove entirely or use a local object.
9. sap.ui.controller() — Controller Definition via Global Factory
Scope: Plain controller definitions. NOT Fiori Elements V2 extensions (use fix-fiori-elements-extensions for those).
Detection: grep -rn 'sap\.ui\.controller(' webapp/ --include="*.js"
- Two arguments
sap.ui.controller("name", {...})= definition → fix here - One argument
sap.ui.controller("name")= instance lookup → document inMODERNIZATION-ISSUES.md
Pattern A: Inside existing sap.ui.define
Pattern B: Without sap.ui.define (legacy module system)
Steps: Remove jQuery.sap.declare/require. Wrap in sap.ui.define. Convert dot-notation deps to slash-notation. Replace sap.ui.controller with Controller.extend. Add return. Add "use strict". Apply all inline fixes to file body (see "Apply ALL" section).
Edge cases
- Missing
return:Controller.extend()only returns the class — always addreturnbefore it - Module-level variables before definition: Keep as-is, just wrap the extend call with
return - Controller name must match file path: Keep existing name even if mismatched (may be intentional)
- Mixed file (definition + instance lookups): Fix the definition, document instance lookups in
MODERNIZATION-ISSUES.md
10. jQuery.sap.declare/require — Legacy Module Definitions
Same structural conversion as Case 9 Pattern B but for non-controller modules:
Key rules: Remove jQuery.sap.declare. Convert jQuery.sap.require to deps. Remove global assignment, return the object. If already has sap.ui.define, merge remaining requires into existing dep array. Dynamic/conditional requires → sap.ui.require(["..."], callback). Multiple declares or unclear exports → flag for manual review. Apply all inline fixes (see "Apply ALL" section).
11. Runtime Globals as Module Imports
Problem: Runtime modules like sap.ushell.Container accessed via global namespace chains.
Test-side: Stub the imported module directly with sinon. Do NOT set up global namespace chains (window.sap.ushell = {...}). sinon and QUnit are Test Starter globals — no import needed.
12. Sync XHR Guards After jQuery.sap.sjax Modernization
After modernizing jQuery.sap.sjax to native XMLHttpRequest, always guard xhr.responseText with a status check:
CRITICAL: Apply ALL Applicable Cases in a Single Pass
When a file triggers Case 9 or 10, fix ALL global-access patterns in the same pass:
jQuery("#...")orjQuery(...)calls? → Case 4a or 4sap.ui.getCore().byId(...)calls? → Case 2, then Case 4a if in controllerjQuery.sap.*calls? → Case 4bsap.ui.model.*,sap.m.*,sap.ui.core.*inline class references? → dependency imports- App-namespace global references? → dependency imports
- Unused imports after replacements? → remove from dep array and parameters
this.X = importedModule.Xwherethis.Xis never read elsewhere? → DELETE (dead code)
Implementation Steps
- Run
npx @ui5/linter --detailsto get replacement suggestions - Identify error pattern and determine case type
- Apply the appropriate transformation (add deps, replace globals, remove dead code)
- After replacing jQuery DOM lookups with
this.byId(), remove unused imports - Verify no other files depend on a removed global assignment
Notes
-
Dependency insertion position — critical: Always add new dependencies at the beginning of the array (and corresponding parameters at the beginning of the function). Many legacy files have dep/param count mismatches (trailing side-effect imports without parameters). Inserting at the end shifts existing mappings; inserting at the beginning preserves them.
-
Parameter names should match the module's default export name (e.g.,
Logforsap/base/Log) -
QUnit,sinonare intentionally allowed globals in test files -
sap.ui.define,sap.ui.require,sap.ui.loader.configare allowed globals -
Use
sap.ui.require("module/path")(sync, returns undefined if not loaded) for optional deps -
Use
sap.ui.require(["module/path"], callback)(async) for lazy loading
Example Fix Session
For a comprehensive before/after example combining multiple case types, read references/example-fix-session.md.
Related Skills
- fix-fiori-elements-extensions: For
sap.ui.controller()in Fiori Elements V2 apps withregisterControllerExtensionsor manifestsap.ui.controllerExtensions - fix-pseudo-modules: For
no-pseudo-modulesandno-implicit-globalserrors (enum imports, DataType imports, OData expression functions) - fix-control-renderer: For renderer-specific issues (
no-deprecated-control-renderer-declaration,apiVersion,IconPool,rerender) - fix-xml-globals: For
no-globalsin XML views/fragments (formatters, event handlers viacore:require) - fix-linter-blind-spots: For runtime-breaking global namespace patterns the linter doesn't detect (app-specific namespaces outside
sap.*). Cases 1b and 1c overlap with patterns 1-4 in that skill. - fix-cyclic-deps: When Case 1c fixes would create cyclic dependencies, use lazy
sap.ui.requireinstead of normalsap.ui.definedeps


