Lesson 2 of 6
Finding problems: UI5 linter and the migration tool
11 min
Listen to this lesson
You cannot plan remediation without knowing where the problems are, and nobody reads 38 apps line by line. SAP's open-source UI5 linter does that work: it scans JavaScript, TypeScript, XML views, HTML, manifest files and ui5.yaml, and reports deprecated APIs, globals, sync loading patterns, CSP problems and more. SAP's best-practices page lists it as a prerequisite: use the UI5 linter to find and remove legacy code.
Running the linter
- Install it in the project as a dev dependency:
npm install --save-dev @ui5/linter. It needs a current Node.js version (check the project README; v20.11 or v22 and later at the time of writing). - Run
npx ui5lintin the app root. The default output groups findings by file with rule IDs. - Add
--detailsto see how to fix each finding. - For reports and dashboards, use
--format json,markdownorhtml. - Exclude generated or third-party files with
--ignore-patternor aui5lint.config.jsfile, and record every exclusion. - Run
ui5lint --fixonly on a clean working tree, review the diff, and run the tests. SetUI5LINT_FIX_DRY_RUN=truefirst to preview.
| Rule ID | What it finds | Example at Contoso |
|---|---|---|
no-deprecated-api | Deprecated APIs, properties, modules and model types | sap.ui.getCore(), the tap event |
no-globals | UI5 globals in code | new sap.m.Button(...) |
no-implicit-globals | Modules reached via library namespaces; implicit odata globals in bindings | odata.compare in an expression binding without a require |
async-component-flags | Component not set up for async loading | Missing IAsyncContentCreation |
csp-unsafe-inline-script | Inline scripts in HTML that conflict with CSP | Bootstrap code inside index.html |
no-deprecated-library | Deprecated libraries in manifest.json or ui5.yaml | sap.ui.commons |
no-deprecated-theme | Deprecated themes in code and HTML | An old theme forced in the bootstrap |
no-pseudo-modules | Dependencies on pseudo modules | Enums required as their own module |
prefer-test-starter | Tests not using the Test Starter | An old QUnit HTML page per test |
no-outdated-manifest-version | Manifest not at Manifest Version 2 | A 2017 manifest.json |
A selection of UI5 linter rules (see the linter's Rules documentation for the full, current list).
What --fix can and cannot do
The linter's autofix handles a defined set of cases: replacing globals with module imports in JavaScript, replacing some Core and Configuration facade APIs, the tap event with press, a few deprecated control properties, and deprecated bootstrap attributes in HTML. The project documents that many deprecated APIs cannot be fixed automatically. Synchronous patterns in particular usually need a human, because making code asynchronous changes its control flow: code after a now-async call runs before the result is there.
The linter in the pipeline
Run once, the linter gives a baseline. Run on every change, it stops new debt. Contoso adds ui5lint --format json as a step in each app's pipeline (SAP Continuous Integration and Delivery for BTP apps, the team's build job for front-end server apps) and stores the JSON output with the build. In Phase 1 the step only reports. Once an app is baselined, the step fails the build if the number of findings for any rule goes up. New code is held to the best practices from that day on, while the old findings are worked down app by app.
The older migration tool
Before the linter's autofix existed, SAP published a separate open-source UI5 migration tool that rewrote some legacy patterns, such as global access, into module form. Some teams still have it in their toolchain. For new remediation work, Contoso uses the linter, because it is actively developed, covers XML, manifest and HTML as well, and gives the reporting Priya needs. If you use any rewriting tool, treat its output exactly like the linter's: a diff to review and test.
Triage: reading the numbers
| App | Findings | Main rules | First reading |
|---|---|---|---|
| ZCMC_CORE_AGR (Fiori elements V4) | 3 | no-deprecated-api in one controller extension | Small fix in the extension |
| ZCMC_FLEET_STATUS (freestyle, 2019) | 140 | no-globals, async-component-flags | Autofix globals, then async by hand |
| ZCMC_CLAIMS (freestyle, 2016) | 610 | no-globals, no-deprecated-api, csp-unsafe-inline-script | Large; compare with a rebuild |
| ZCMC_DEPOT_MAP (2015) | 880 | no-deprecated-library (sap.ui.commons), JS views | Rebuild candidate |
Illustrative linter results for four of Contoso's apps. The count matters less than which rules dominate.
A thousand no-globals findings may disappear with one autofix run; thirty sync-loading findings may take a week. Kenji's triage therefore weights findings by rule, not by count, and every app gets a short note: fixable by tool, fixable by hand, or rebuild.
What goes wrong
- Linting the build output. Run the linter on sources, not on a bundled
distfolder. - Silent exclusions. An ignore pattern that hides half the app makes the dashboard green and the app no better.
- Autofix without tests. The diff looks mechanical; the async timing change is not.
- Counting instead of reading. Effort follows rule types, not totals.
What would you do?
Kenji runs ui5lint --fix on ZCMC_FLEET_STATUS and the findings drop from 140 to 35. He proposes to transport the change today because "the linter fixed it". What should Priya ask for first?
- The UI5 linter (@ui5/linter, command ui5lint) scans JS, TS, XML, HTML, manifest and ui5.yaml.
- Use --details for fixes, --format json/markdown/html for reports, and record every ignore pattern.
- --fix handles globals and some deprecated APIs; sync-to-async changes usually need a developer.
- Triage by rule type, not by count; every autofix is a change to test.
Check your understanding · not graded
Lesson check
1. Which command runs the UI5 linter in a project?
2. Which rule reports sap.ui.commons in manifest.json?
3. How do you preview autofix changes without writing files?
4. Why do sync-to-async changes usually need a developer?
5. What should drive remediation effort estimates?