Now accepting guest editorial from SAP, Oracle, Workday and ServiceNow practitioners.Pitch a guide
The Sign-Off Table

Lesson 2 of 6

Finding problems: UI5 linter and the migration tool

11 min

Listen to this lesson

0:00 / 9:00

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

  1. 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).
  2. Run npx ui5lint in the app root. The default output groups findings by file with rule IDs.
  3. Add --details to see how to fix each finding.
  4. For reports and dashboards, use --format json, markdown or html.
  5. Exclude generated or third-party files with --ignore-pattern or a ui5lint.config.js file, and record every exclusion.
  6. Run ui5lint --fix only on a clean working tree, review the diff, and run the tests. Set UI5LINT_FIX_DRY_RUN=true first to preview.
Rule IDWhat it findsExample at Contoso
no-deprecated-apiDeprecated APIs, properties, modules and model typessap.ui.getCore(), the tap event
no-globalsUI5 globals in codenew sap.m.Button(...)
no-implicit-globalsModules reached via library namespaces; implicit odata globals in bindingsodata.compare in an expression binding without a require
async-component-flagsComponent not set up for async loadingMissing IAsyncContentCreation
csp-unsafe-inline-scriptInline scripts in HTML that conflict with CSPBootstrap code inside index.html
no-deprecated-libraryDeprecated libraries in manifest.json or ui5.yamlsap.ui.commons
no-deprecated-themeDeprecated themes in code and HTMLAn old theme forced in the bootstrap
no-pseudo-modulesDependencies on pseudo modulesEnums required as their own module
prefer-test-starterTests not using the Test StarterAn old QUnit HTML page per test
no-outdated-manifest-versionManifest not at Manifest Version 2A 2017 manifest.json

A selection of UI5 linter rules (see the linter's Rules documentation for the full, current list).

The linter loop for one app: measure, triage, fix what can be fixed automatically, prove with tests.
The Sign-Off Table · thesignofftable.com/academy/sap-btp-206

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.

Autofix with a safety net: dry run, fix, then the test suite decides. Here two journeys fail because code now runs asynchronously.
The Sign-Off Table · thesignofftable.com/academy/sap-btp-206

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

AppFindingsMain rulesFirst reading
ZCMC_CORE_AGR (Fiori elements V4)3no-deprecated-api in one controller extensionSmall fix in the extension
ZCMC_FLEET_STATUS (freestyle, 2019)140no-globals, async-component-flagsAutofix globals, then async by hand
ZCMC_CLAIMS (freestyle, 2016)610no-globals, no-deprecated-api, csp-unsafe-inline-scriptLarge; compare with a rebuild
ZCMC_DEPOT_MAP (2015)880no-deprecated-library (sap.ui.commons), JS viewsRebuild candidate

Illustrative linter results for four of Contoso's apps. The count matters less than which rules dominate.

Hand fix, low riskDeprecated control properties, themes, manifest version
Tool fix, low riskno-globals in JavaScript, tap to press, bootstrap attributes
Hand fix, high riskSync loading and sync XHR, JS and HTML views, deprecated libraries
Tool fix, check carefullyCore facade replacements that change when code runs
Linter findings sorted by how they get fixed, which drives effort far more than the raw count.
The Sign-Off Table · thesignofftable.com/academy/sap-btp-206

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 dist folder.
  • 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?

Key points
  • 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. 1. Which command runs the UI5 linter in a project?

  2. 2. Which rule reports sap.ui.commons in manifest.json?

  3. 3. How do you preview autofix changes without writing files?

  4. 4. Why do sync-to-async changes usually need a developer?

  5. 5. What should drive remediation effort estimates?