Source 1aec6c0605b0200335546aff
ASecurityHandle Fiori Elements V2 controller extensions during UI5 modernization. Use this skill when: - Extension controllers use `sap.ui.controller()` AND the manifest has a matching `controllerName` entry (Case B → report only, do not modernize) - Extension controllers use `Controller.extend()` with manifest `controllerName` registration (Case B → report only, do not modernize) - Code contains `registerControllerExtensions` calls (Case A → ControllerExtension.extend + override) - Manifest.json has ...
- 2 stars
- 0 votes
- 0 copies
- 0 views
- Added November 7, 2026
Works with
Security analysis
100/100Pro scans all 3 files and shows the line behind each finding
npx -y skills add gutsofpratik/OpenClaude-Skills --skill source-1aec6c0605b0200335546aff --agent claude-codeAre you the author of Source 1aec6c0605b0200335546aff?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/gutsofpratik-source-1aec6c0605b0200335546aff)---
name: fix-fiori-elements-extensions
description: |
Handle Fiori Elements V2 controller extensions during UI5 modernization. Use this skill when:
- Extension controllers use `sap.ui.controller()` AND the manifest has a matching `controllerName` entry (Case B → report only, do not modernize)
- Extension controllers use `Controller.extend()` with manifest `controllerName` registration (Case B → report only, do not modernize)
- Code contains `registerControllerExtensions` calls (Case A → ControllerExtension.extend + override)
- Manifest.json has `sap.ui5/extends/extensions/sap.ui.controllerExtensions` with `controllerName` entries
Case B (plain object) is by far the most common. For Case B, do NOT modify controller files — report them and move on. Case A requires actual code modernization.
For plain controller definitions in custom (non-Fiori-Elements) apps where `sap.ui.controller()` is just defining a standalone controller, use `fix-js-globals` (Case 9) instead.
---
# Fix Fiori Elements Controller Extensions
This skill handles Fiori Elements V2 controller extensions during UI5 modernization. There are two cases with different actions:
- **Case B (most common)**: Extensions registered via `controllerName` in manifest → **Report only. Do NOT modify the controller files.** Leave them as-is and inform the user which files need manual attention.
- **Case A (rare)**: Extensions using `registerControllerExtensions` → Perform the full modernization to `ControllerExtension.extend()` + manifest registration.
## Linter Rules Handled
| Rule ID | Message Pattern | This Skill's Action |
|---------|-----------------|---------------------|
| `no-deprecated-api` | Use of deprecated `registerControllerExtensions` | Case A: Modernize to manifest + ControllerExtension |
| `no-deprecated-api` | Use of deprecated `sap.ui.controller` | Case B (if manifest has `controllerName`): **report only, do not fix**; Case A (if `registerControllerExtensions`): ControllerExtension class |
| `no-deprecated-api` | Use of deprecated `Controller` (from `sap/ui/core/mvc/Controller`) | Case B: **report only, do not fix** |
## Quick Decision: Which Case Am I?
```
Is there a `controllerName` entry in manifest.json under
sap.ui5/extends/extensions/sap.ui.controllerExtensions with a SIMPLE key
(no "#" in the key)?
├── YES → Case B: DO NOT MODERNIZE. Report the file(s) and move on.
│ (regardless of whether source uses sap.ui.controller() or Controller.extend())
└── NO → Is there a registerControllerExtensions call in JS?
├── YES → Case A: modernize to ControllerExtension.extend() + manifest with #stableId key
└── NO → This skill does not apply
```
## When to Use
**Case B (most common)** — Detected when the manifest already has a `controllerName` entry under a simple key, and the controller file uses either `sap.ui.controller()` or `Controller.extend()`:
```json
// manifest.json — controllerName registration already present (simple key, no "#")
"sap.ui.controllerExtensions": {
"sap.suite.ui.generic.template.ListReport.view.ListReport": {
"controllerName": "my.app.ext.controller.ListReportExt"
}
}
```
The source controller might look like either of these:
```javascript
// Variant 1: sap.ui.controller() — NO sap.ui.define wrapper
sap.ui.controller("my.app.ext.controller.ListReportExt", {
onInit: function() { ... },
onCustomAction: function() { ... }
});
```
```javascript
// Variant 2: Controller.extend() — inside sap.ui.define
sap.ui.define(["sap/ui/core/mvc/Controller", ...], function(Controller, ...) {
return Controller.extend("my.app.ext.controller.ListReportExt", { ... });
});
```
Linter output triggering Case B:
```
MyExtension.controller.js:1:1 error Use of deprecated function 'sap.ui.controller' no-deprecated-api
MyExtension.controller.js:3:5 error Use of deprecated function 'Controller' (from 'sap/ui/core/mvc/Controller') no-deprecated-api
```
> **Action for Case B: Do NOT modify these files.** Report them to the user and continue with the rest of the modernization.
**Case A (rare, older apps only)** — Apply when you see linter output like:
```
Component.js:25:5 error Use of deprecated function 'registerControllerExtensions' no-deprecated-api
```
Or when an app has patterns like:
```javascript
// In Component.js or elsewhere — NO manifest entry exists yet
this.getExtensionComponent().registerControllerExtensions("sap.suite.ui.generic.template.ListReport.view.ListReport", {
onInit: function() { ... },
onAction: function() { ... }
});
```
## Fix Strategy
The action depends on **how the extension is registered in the manifest**. Determine which case applies before proceeding.
### Case Detection
| Manifest Registration | Source Code (any of) | Action |
|---|---|---|
| `controllerName` in manifest (simple key, no `#stableId`) | `sap.ui.controller()`, `Controller.extend()`, or plain object | **Case B: Report only — do NOT modify files** |
| `registerControllerExtensions` in JS (no manifest entry) | `sap.ui.controller()` or inline object | Case A: `ControllerExtension.extend()` + `override` + add manifest entry with `#stableId` key |
**The key differentiator is the manifest registration format:**
- **Case B** (most common): `controllerName` already in manifest under a **simple key** (e.g., `"sap.suite.ui.generic.template.ListReport.view.ListReport": { "controllerName": "..." }`). **Do not modernize these files.** Report them and move on.
- **Case A**: No `controllerName` in manifest yet — extension is registered programmatically via `registerControllerExtensions`. The modernization adds a manifest entry with the `#stableId` key format AND uses `ControllerExtension.extend()`.
**Detection commands:**
```bash
# Check manifest registration format
grep -B1 -A2 "controllerName" webapp/manifest.json
# Case B indicator: controllerName in manifest with simple key (no # in key)
# If the key does NOT contain "#", it's the merging mechanism → Case B → REPORT ONLY
# Case A indicator: registerControllerExtensions in JS
grep -rl "registerControllerExtensions" webapp/ --include="*.js"
```
---
### Case B: Report and Skip (Most Common)
For extensions registered via `controllerName` in the manifest (simple key without `#stableId`), **do NOT modify the controller files**. These require careful manual modernization and are left to the developer.
**Steps:**
1. Identify all controller files referenced by `controllerName` entries in manifest.json (under keys that do NOT contain `#`)
2. Report them to the user with this format:
```
⚠️ Fiori Elements controller extensions (Case B) — skipped, requires manual modernization:
- webapp/ext/controller/ListReportExt.controller.js
- webapp/ext/controller/ObjectPageExt.controller.js
These files use deprecated APIs (sap.ui.controller / Controller.extend) but are Fiori Elements
controller extensions registered via controllerName in the manifest. They require careful manual
modernization to a plain-object return pattern. The linter errors for these files will persist until
they are modernized manually.
```
3. **Do NOT** (within this skill):
- Modify the controller .js files to change the controller extension pattern (no plain-object conversion)
- Change the manifest registration
- Add linter disable comments
- Attempt the plain-object modernization pattern
4. **Other skills CAN still process these files** for unrelated fixes (e.g., `fix-js-globals` replacing `sap.ui.getCore()` calls within method bodies, `fix-linter-blind-spots` for namespace patterns). Only the `sap.ui.controller()` / `Controller.extend()` structure itself is left untouched.
5. Continue with the rest of the modernization (other skills, other linter findings)
---
### Case A: Step 1 — Move Registration from JS to manifest.json
*Only for Case A (extensions using `registerControllerExtensions` in JS).*
Move controller extension registrations from JavaScript code to the manifest under `sap.ui.controllerExtensions`.
**Key format**: `<FLOORPLAN_CONTROLLER>#<STABLE_ID_OF_VIEW>`
```json
// Before - no controller extensions in manifest
// After - manifest.json
{
"sap.ui5": {
"extends": {
"extensions": {
"sap.ui.controllerExtensions": {
"sap.suite.ui.generic.template.ListReport.view.ListReport#myApp::sap.suite.ui.generic.template.ListReport.view.ListReport::EntitySet": {
"controllerName": "my.app.ext.ListReportExtension"
},
"sap.suite.ui.generic.template.ObjectPage.view.Details#myApp::sap.suite.ui.generic.template.ObjectPage.view.Details::EntitySet": {
"controllerName": "my.app.ext.ObjectPageExtension"
}
}
}
}
}
}
```
**Finding the correct key:**
1. The key has format: `<FloorplanController>#<StableViewId>`
2. The floorplan controller name matches the view name (e.g., `sap.suite.ui.generic.template.ListReport.view.ListReport`)
3. The stable view ID is typically: `<AppId>::<FloorplanViewName>::<EntitySet>`
4. Check the app's existing manifest for `sap.ui.generic.app` / `pages` configuration to find entity sets and page IDs
### Case A: Step 2 — Restructure Controller Files
> **⚠️ This step only applies to Case A** (extensions using `sap.ui.controller()` factory).
> If the extension already uses `Controller.extend()` with manifest `controllerName` registration, use **Case B** below instead.
Convert controller files from `sap.ui.controller` style to `ControllerExtension` class.
**Before:**
```javascript
sap.ui.controller("my.app.ext.ListReportExtension", {
onInit: function() {
// lifecycle code
},
onBeforeRebindTable: function(oEvent) {
// framework override
},
onCustomAction: function(oEvent) {
// custom method
}
});
```
**After:**
```javascript
sap.ui.define([
"sap/ui/core/mvc/ControllerExtension"
], function(ControllerExtension) {
"use strict";
return ControllerExtension.extend("my.app.ext.ListReportExtension", {
// Lifecycle and framework overrides go inside "override"
override: {
onInit: function() {
// extensionAPI is injected by the framework into the extension instance
this._extensionAPI = this.extensionAPI;
},
onBeforeRebindTable: function(oEvent) {
// framework override
}
},
// Custom methods go OUTSIDE "override"
onCustomAction: function(oEvent) {
// custom method
}
});
});
```
**Key rules for restructuring:**
- Extend `sap/ui/core/mvc/ControllerExtension` instead of using `sap.ui.controller`
- **Lifecycle methods** (`onInit`, `onExit`, `onBeforeRendering`, `onAfterRendering`) → inside `override`
- **Framework callback methods** (`onBeforeRebindTable`, `onBeforeRebindChart`, `onListNavigationExtension`, `adaptNavigationParameterExtension`, etc.) → inside `override`
- **Custom action methods** (handlers for custom buttons/actions) → OUTSIDE `override`
- Access `extensionAPI` via `this.extensionAPI` (the framework injects it into the extension instance)
---
### Case A: Step 3 — Update Handler References
In the manifest and XML annotations, update all event handler references from the old format to the new qualified format.
**Before:**
```json
// In manifest extensions or annotations
"Actions": {
"MyAction": {
"id": "MyAction",
"text": "Do Something",
"press": "onCustomAction"
}
}
```
**After:**
```json
"Actions": {
"MyAction": {
"id": "MyAction",
"text": "Do Something",
"press": ".extension.my.app.ext.ListReportExtension.onCustomAction"
}
}
```
**Reference format**: `.extension.<full.controller.name>.<methodName>`
**Important**: Use the **dotted module name** as declared in `ControllerExtension.extend("my.app.ext.ListReportExtension", ...)` and in the manifest's `controllerName` — **not** the slash-separated path used in `sap.ui.define` imports (e.g., `"my/app/ext/ListReportExtension"`).
This applies to:
- `press` handlers in manifest action definitions
- Custom column/section handler references
- Any event handler references that previously used just the method name
## Implementation Steps
### Case B Implementation (Report Only)
1. **Identify extension controllers** registered via `controllerName` in manifest (simple key, no `#`)
2. **Report them** to the user — list each file path and note that they require manual modernization
3. **Do not modify** these files, their manifest entries, or their handler references
4. **Continue** with other modernization tasks
### Case A Implementation (registerControllerExtensions → ControllerExtension)
1. **Identify all `registerControllerExtensions` calls** in the codebase (typically in Component.js or helper files)
2. **For each registration**:
a. Determine the floorplan controller name and view stable ID
b. Determine the extension controller name/path
c. Add entry to `manifest.json` under `sap.ui5/extends/extensions/sap.ui.controllerExtensions`
3. **For each extension controller file**:
a. Replace `sap.ui.controller(...)` with `sap.ui.define([ControllerExtension], ...)`
b. Move lifecycle/framework methods into `override` section
c. Keep custom methods outside `override`
d. Update `extensionAPI` access pattern
4. **For all handler references**:
a. Search manifest.json for action `press` handlers using simple method names
b. Search XML annotation files for handler references
c. Update to `.extension.<module>.<method>` format
5. **Remove the `registerControllerExtensions` calls** from Component.js
6. **Verify** by re-running the linter
## Example Full Modernization
**Before — Component.js:**
```javascript
sap.ui.define([
"sap/suite/ui/generic/template/lib/AppComponent"
], function(AppComponent) {
"use strict";
return AppComponent.extend("my.app.Component", {
metadata: {
manifest: "json"
},
init: function() {
AppComponent.prototype.init.apply(this, arguments);
this.getExtensionComponent().registerControllerExtensions(
"sap.suite.ui.generic.template.ListReport.view.ListReport", {
onInit: function() {
// lifecycle code
},
onCustomAction: function(oEvent) {
// custom handler
}
}
);
}
});
});
```
**After — Component.js:**
```javascript
sap.ui.define([
"sap/suite/ui/generic/template/lib/AppComponent"
], function(AppComponent) {
"use strict";
return AppComponent.extend("my.app.Component", {
metadata: {
manifest: "json"
}
// registerControllerExtensions call removed — now in manifest.json
});
});
```
**After — manifest.json (additions):**
```json
{
"sap.ui5": {
"extends": {
"extensions": {
"sap.ui.controllerExtensions": {
"sap.suite.ui.generic.template.ListReport.view.ListReport#my.app::sap.suite.ui.generic.template.ListReport.view.ListReport::Products": {
"controllerName": "my.app.ext.ListReportExtension"
}
}
}
}
}
}
```
**After — ext/ListReportExtension.controller.js:**
```javascript
sap.ui.define([
"sap/ui/core/mvc/ControllerExtension"
], function(ControllerExtension) {
"use strict";
return ControllerExtension.extend("my.app.ext.ListReportExtension", {
override: {
onInit: function() {
this._extensionAPI = this.extensionAPI;
}
},
onCustomAction: function(oEvent) {
// Custom action handler — accessible as
// ".extension.my.app.ext.ListReportExtension.onCustomAction"
}
});
});
```
## Notes
- This modernization only applies to **Fiori Elements V2** template apps (using `sap.suite.ui.generic.template`)
- Fiori Elements V4 (using `sap.fe.templates`) uses a different extension mechanism — this skill does not apply
- **Case B is far more common** in practice — extensions registered via `controllerName` in the manifest. These are **not auto-modernized** — the agent reports them and moves on
- Case A only appears in older apps that never modernized from `registerControllerExtensions`
- The stable view ID format varies by floorplan and configuration — check the running app's DOM or the floorplan documentation
- If the app uses `templateSpecific.json` for handler references, those must also be updated (Case A only)
- After Case A modernization, the extension controller file should be placed under a path matching its module name
## Related Skills
- **fix-js-globals**: For plain `sap.ui.controller()` definitions in custom apps (Case 9), or if extension controllers also use global access patterns (`sap.ui.getCore()`, `jQuery.sap.*`). Other skills CAN still be applied to Case B controller files for issues unrelated to the controller extension pattern itself (e.g., replacing global API usage within method bodies).
- **fix-manifest-json**: The manifest changes for controller extensions are additive — they don't conflict with version/routing updates from fix-manifest-json
- **fix-linter-blind-spots**: Can still fix namespace patterns and other blind spots within Case B controller files
Files in this skill
- PROVENANCE.json
- SKILL.md
- UPSTREAM-LICENSE.txt
Attribution
Comments
Loading comments…
Newsletter
Get the weekly list of safe new skills, and the ones we pulled.