From ui5-modernization
Fixes pseudo module access and implicit global issues that UI5 linter detects but cannot auto-fix. Provides guidance on proper module imports for enums, DataTypes, and OData expression addons.
How this skill is triggered — by the user, by Claude, or both
Slash command
/ui5-modernization:fix-pseudo-modulesThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
This skill fixes pseudo module access and implicit global issues that the UI5 linter detects but cannot auto-fix because they require understanding proper module import patterns.
This skill fixes pseudo module access and implicit global issues that the UI5 linter detects but cannot auto-fix because they require understanding proper module import patterns.
| Rule ID | Message Pattern | This Skill's Action |
|---|---|---|
no-pseudo-modules | Deprecated access of enum pseudo module '...' | Import via library module |
no-pseudo-modules | Deprecated access of DataType pseudo module '...' | Import via library module |
no-implicit-globals | Access of module '...' not exported by library '...' | Import module directly |
no-implicit-globals | OData built-in global symbols must not be used implicitly | Import ODataExpressionAddons |
Apply this skill when you see linter output like:
MyController.js:5:5 error Deprecated access of enum pseudo module 'sap/ui/core/BarColor' no-pseudo-modules
MyController.js:8:5 error Deprecated access of DataType pseudo module 'sap/ui/core/CSSSize' no-pseudo-modules
MyController.js:15:5 error Access of module 'sap/ui/unified/DateRange' not exported by library 'sap/ui/unified/library' no-implicit-globals
MyView.view.xml:20:5 error OData built-in global symbols must not be used implicitly no-implicit-globals
In UI5, enums and DataTypes were historically accessed as if they were modules (e.g., sap/ui/core/BarColor). These are "pseudo modules" - they don't exist as real files but are resolved at runtime from the library module. In modern UI5, direct pseudo module imports are deprecated.
Problem: Importing enums as direct modules.
// Before - triggers no-pseudo-modules
sap.ui.define([
"sap/ui/core/mvc/Controller",
"sap/ui/core/BarColor", // Pseudo module!
"sap/m/ListSeparators" // Pseudo module!
], function(Controller, BarColor, ListSeparators) {
"use strict";
return Controller.extend("my.app.controller.Main", {
onInit: function() {
var color = BarColor.Positive;
var separator = ListSeparators.All;
}
});
});
Fix Strategy: Import from the library module and access the enum as a property.
// After - import from library
sap.ui.define([
"sap/ui/core/mvc/Controller",
"sap/ui/core/library", // Import library
"sap/m/library" // Import library
], function(Controller, coreLibrary, mLibrary) {
"use strict";
// Extract enums from library
var BarColor = coreLibrary.BarColor;
var ListSeparators = mLibrary.ListSeparators;
return Controller.extend("my.app.controller.Main", {
onInit: function() {
var color = BarColor.Positive;
var separator = ListSeparators.All;
}
});
});
Common Enum Pseudo Modules and Their Libraries:
| Pseudo Module | Library Module | Enum Access |
|---|---|---|
sap/ui/core/BarColor | sap/ui/core/library | coreLibrary.BarColor |
sap/ui/core/ValueState | sap/ui/core/library | coreLibrary.ValueState |
sap/ui/core/TextDirection | sap/ui/core/library | coreLibrary.TextDirection |
sap/ui/core/TextAlign | sap/ui/core/library | coreLibrary.TextAlign |
sap/ui/core/MessageType | sap/ui/core/library | coreLibrary.MessageType |
sap/m/ListSeparators | sap/m/library | mLibrary.ListSeparators |
sap/m/ListMode | sap/m/library | mLibrary.ListMode |
sap/m/ListType | sap/m/library | mLibrary.ListType |
sap/m/ButtonType | sap/m/library | mLibrary.ButtonType |
sap/m/InputType | sap/m/library | mLibrary.InputType |
Problem: Importing DataTypes as direct modules.
// Before - triggers no-pseudo-modules
sap.ui.define([
"sap/ui/core/mvc/Controller",
"sap/ui/core/CSSSize" // DataType pseudo module!
], function(Controller, CSSSize) {
"use strict";
return Controller.extend("my.app.controller.Main", {
// Using CSSSize type
});
});
Fix Strategy: Import from the library module.
// After - import from library
sap.ui.define([
"sap/ui/core/mvc/Controller",
"sap/ui/core/library"
], function(Controller, coreLibrary) {
"use strict";
var CSSSize = coreLibrary.CSSSize;
return Controller.extend("my.app.controller.Main", {
// Using CSSSize type
});
});
Common DataType Pseudo Modules:
| Pseudo Module | Library Module |
|---|---|
sap/ui/core/CSSSize | sap/ui/core/library |
sap/ui/core/CSSColor | sap/ui/core/library |
sap/ui/core/URI | sap/ui/core/library |
sap/ui/core/ID | sap/ui/core/library |
sap/ui/core/Percentage | sap/ui/core/library |
Problem: Accessing modules via library exports that aren't actually exported.
// Before - triggers no-implicit-globals
sap.ui.define([
"sap/ui/unified/library",
"sap/ui/core/library"
], function(unifiedLibrary, coreLibrary) {
"use strict";
// These modules are NOT exported by the library!
var DateRange = unifiedLibrary.DateRange; // Error
var DOMAttribute = coreLibrary.tmpl.DOMAttribute; // Error
});
Fix Strategy: Import the module directly.
// After - import modules directly
sap.ui.define([
"sap/ui/unified/DateRange", // Direct import
"sap/ui/core/tmpl/DOMAttribute" // Direct import
], function(DateRange, DOMAttribute) {
"use strict";
// Use directly
});
Rule of Thumb:
library.EnumName)sap/ui/unified/DateRange)Problem: Using OData built-in functions in expression bindings without importing.
// Before - triggers no-implicit-globals
sap.ui.define([
"sap/ui/core/mvc/Controller",
"sap/m/Text"
], function(Controller, Text) {
"use strict";
return Controller.extend("my.app.controller.Main", {
onInit: function() {
var oText = new Text({
// Using odata.compare without import!
text: "{= odata.compare(${/value1}, ${/value2}) }"
});
}
});
});
Fix Strategy: Import ODataExpressionAddons module.
// After - import ODataExpressionAddons
sap.ui.define([
"sap/ui/core/mvc/Controller",
"sap/m/Text",
"sap/ui/model/odata/ODataExpressionAddons" // Required for odata.* functions
], function(Controller, Text, ODataExpressionAddons) {
"use strict";
return Controller.extend("my.app.controller.Main", {
onInit: function() {
var oText = new Text({
// Now works - ODataExpressionAddons is imported
text: "{= odata.compare(${/value1}, ${/value2}) }"
});
}
});
});
OData Functions Requiring Import:
| OData Function | Alternative Direct Module |
|---|---|
odata.compare | sap/ui/model/odata/v4/ODataUtils |
odata.fillUriTemplate | sap/ui/thirdparty/URITemplate |
odata.uriEncode | sap/ui/model/odata/ODataUtils |
Note: Importing sap/ui/model/odata/ODataExpressionAddons is the simplest solution as it registers all OData expression functions.
Problem: Using OData functions in XML view bindings without import.
<!-- Before - triggers no-implicit-globals -->
<mvc:View
xmlns:mvc="sap.ui.core.mvc"
xmlns="sap.m">
<Text text="{= odata.compare(${/price1}, ${/price2}) }" />
</mvc:View>
Fix Strategy: Add core:require for ODataExpressionAddons.
<!-- After - with core:require -->
<mvc:View
xmlns:mvc="sap.ui.core.mvc"
xmlns="sap.m"
xmlns:core="sap.ui.core"
core:require="{
ODataAddons: 'sap/ui/model/odata/ODataExpressionAddons'
}">
<Text text="{= odata.compare(${/price1}, ${/price2}) }" />
</mvc:View>
Identify the issue type from the linter message:
Determine the correct library for enums/DataTypes:
sap/ui/core/ → sap/ui/core/library)Update imports:
Update code references:
var EnumName = library.EnumName;For XML views: Add core:require when needed
Given linter output:
MyController.js:3:5 error Deprecated access of enum pseudo module 'sap/ui/core/ValueState' no-pseudo-modules
MyController.js:4:5 error Access of module 'sap/ui/unified/DateRange' not exported by library 'sap/ui/unified/library' no-implicit-globals
MyController.js:25:5 error OData built-in global symbols must not be used implicitly no-implicit-globals
Before:
sap.ui.define([
"sap/ui/core/mvc/Controller",
"sap/ui/core/ValueState",
"sap/ui/unified/library"
], function(Controller, ValueState, unifiedLibrary) {
"use strict";
var DateRange = unifiedLibrary.DateRange; // Error: not exported
return Controller.extend("my.app.controller.Main", {
onInit: function() {
var state = ValueState.Error;
var oDateRange = new DateRange({
startDate: new Date()
});
},
formatComparison: function() {
return "{= odata.compare(${/val1}, ${/val2}) }"; // Error: no import
}
});
});
After:
sap.ui.define([
"sap/ui/core/mvc/Controller",
"sap/ui/core/library", // For ValueState enum
"sap/ui/unified/DateRange", // Direct import
"sap/ui/model/odata/ODataExpressionAddons" // For odata.* functions
], function(Controller, coreLibrary, DateRange, ODataExpressionAddons) {
"use strict";
var ValueState = coreLibrary.ValueState; // Extract from library
return Controller.extend("my.app.controller.Main", {
onInit: function() {
var state = ValueState.Error;
var oDateRange = new DateRange({
startDate: new Date()
});
},
formatComparison: function() {
return "{= odata.compare(${/val1}, ${/val2}) }"; // Now works
}
});
});
ODataExpressionAddons import is needed even though you don't use the variable directly - it registers the functions at load timeno-globals on JS files — e.g., sap.ui.getCore(), jQuery, sap.ui.controller()), use fix-js-globalsclaude plugin install ui5-modernization@claude-plugins-officialFixes Library.init() apiVersion issues and modernizes enum definitions to DataType.registerEnum in UI5 library.js files.
Enforces SAP UI5 coding standards including async loading, ComponentSupport, CSP compliance, OData binding, i18n, TypeScript events, CAP integration, and form layouts (Form with ColumnLayout).
Converts UI5 (SAPUI5/OpenUI5) projects to TypeScript with step-by-step guidance on setup, code conversion, and test migration. Preserves comments, avoids `any`, and uses proper UI5 types.