Fiori ESLint Rule Developer
Add a new ESLint rule to
@sap-ux/eslint-plugin-fiori-tools
following the established patterns in the monorepo.
⚡ Efficiency rules — read before doing anything
- Use the tool directly — never or spawn Explore subagents for file reading
- Read everything in one parallel batch — each fast path lists the exact files; read them all at once in a single turn
- Run only the new test file during development — not the full package suite:
bash
NODE_OPTIONS="--experimental-vm-modules" npx jest --testPathPatterns="sap-[rule-name]" --no-coverage
Step 1 — Identify the rule type, then read the reference file
| Type | Use when | Reference file |
|---|
| Annotation rule | Validates OData annotations in / files | |
| Manifest JSON rule | Validates properties | references/manifest-json.md
|
| Flex change file rule | Validates (Applicable only to OData V2 flex change properties) | references/flex-change.md
|
| JavaScript / TypeScript rule | Validates JS/TS application source code (UI5 patterns, global variables, deprecated APIs) | |
Infer from the request:
- Rule name — pattern
- OData version — V2 only, V4 only, or both
- Page scope — which page types to check. Default: all page types (list report, object page, etc.) unless the spec explicitly restricts the scope. Do not limit to one page type based on the examples in the spec.
- Auto-fix — yes/no
- Severity — or . Rules in MUST be .
OData version determines the linker file — always follow the stated version:
| OData version | Linker file | Manifest root |
|---|
| V2 only | src/project-context/linker/fe-v2.ts
| sap.ui.generic.app.pages.*
|
| V4 only | src/project-context/linker/fe-v4.ts
| sap.ui5.routing.targets.*
|
| Both | both linker files | both roots |
Read the matching reference file immediately, then read all the files it lists in a single parallel batch. If the rule spans multiple types (e.g. annotations + manifest, or manifest + flex changes), read all matching reference files and combine their templates and access patterns.
Steps 2–10: Implementation Checklist
Step 2 — Add diagnostic constant (annotation, manifest JSON, and flex change rules only; skip for JS/TS rules)
In
packages/eslint-plugin-fiori-tools/src/language/diagnostics.ts
:
typescript
export const MY_RULE = 'sap-my-new-rule';
export interface MyRuleDiagnostic {
type: typeof MY_RULE;
// ... fields from the reference file's "Required diagnostic fields" table
}
// Add MyRuleDiagnostic to the Diagnostic union at the bottom
Step 3 — Implement the rule
Use the template from the reference file for your rule type.
Code quality requirements for every new or modified function:
- JSDoc — add a JSDoc block (, ) to every new function. When modifying an existing function, update its JSDoc to reflect any signature or behaviour changes.
- Cognitive complexity ≤ 15 — enforced by
sonarjs/cognitive-complexity
. If a function exceeds 15, extract branches or loops into well-named helper functions until the complexity falls within the limit. Do not inline complex logic in a single function to avoid this.
Step 4 — Register the rule
— add import + entry (alphabetical order):
typescript
import sapMyNewRule from './sap-my-new-rule.js';
// ...
[MY_RULE]: sapMyNewRule,
— add to
rules (Fiori language rules) or
(JS/TS rules):
typescript
'@sap-ux/fiori-tools/sap-my-new-rule': 'warn',
If the rule should also apply to S/4HANA projects, add it to the
config in
as well. Rules in this config
must use
severity:
typescript
// In the recommended-for-s4hana config rules object:
'@sap-ux/fiori-tools/sap-my-new-rule': 'warn',
Step 5 — Write tests
Use the test template from the reference file; run only the new test file (see efficiency rules at the top).
Always check , never , in arrays. When a rule message contains interpolated data (e.g.
), checking only
would accept any value for that placeholder and miss regressions. Use the fully resolved string instead:
typescript
// ✅ Correct — verifies the interpolated value
errors: [
{
message:
'"TreeTable" is not supported in the flexible column layout with a draft-enabled service.'
}
]
// ❌ Wrong — does not verify the data interpolated into the message
errors: [{ messageId: 'sap-my-new-rule' }]
If tests show 0 errors when violations are expected, check the debug checklist at the bottom of the reference file.
Step 6 — Write documentation
Create
packages/eslint-plugin-fiori-tools/docs/rules/sap-[rule-name].md
.
Read
packages/eslint-plugin-fiori-tools/docs/rules/TEMPLATE.md
for structure. Key sections:
- H1 title — one sentence describing the rule, with the rule ID in parentheses
- Intro paragraph — 2–3 sentences: what it detects, why it was introduced (motivation belongs here, not in a separate H2), and what to do instead
- ## Rule Details — how the rule works; warning message; "The following patterns are considered warnings:" + "The following patterns are not considered warnings" code examples
- ### How to Fix — steps to remediate (omit if obvious from the examples)
- ## False Positives — optional; include only if the rule can produce false positives
- ## Bug Report — link to GitHub issues
- ## Further Reading — optional; only include if you have a real, verifiable URL
Step 7 — Update README
In
packages/eslint-plugin-fiori-tools/README.md
, do
two things:
-
Add your new rule at the
top of the rules table with
in the version column:
markdown
| new | [sap-my-new-rule](docs/rules/sap-my-new-rule.md) | Short description | | ✅ |
-
Backfill any pending versions: if any rows still show
from prior rule additions that have since been released, look up each rule's release version in
packages/eslint-plugin-fiori-tools/CHANGELOG.md
and replace
with that version. After this cleanup, your newly added rule should be the only row showing
.
Step 8 — Run full quality gates (once)
Run
to auto-fix ESLint errors and apply Prettier formatting across all modified files, then verify no issues remain:
bash
# Fix lint errors and apply Prettier formatting
pnpm --filter @sap-ux/eslint-plugin-fiori-tools lint:fix
# Verify no remaining issues
pnpm --filter @sap-ux/eslint-plugin-fiori-tools lint
If
reports errors after
:
sonarjs/cognitive-complexity
— resolve per the cognitive complexity guidance in Step 3.
- — a formatting issue could not be auto-fixed. Apply the suggested change manually (usually a line that is too long or a multiline expression that needs restructuring).
@typescript-eslint/no-unsafe-*
— replace casts or untyped values with proper interfaces or + type guards.
Do not proceed to Step 9 until
exits with code 0.
Then confirm all tests still pass:
bash
pnpm --filter @sap-ux/eslint-plugin-fiori-tools test
Step 9 — Create changeset
Select
@sap-ux/eslint-plugin-fiori-tools
, choose
for new rules:
FEAT: add sap-my-new-rule rule for [short description]
Step 10 — Report
Summarize what was done:
- Rule name and type — rule ID and which type (annotation / manifest JSON / flex change / JS/TS)
- Files created — rule implementation, test file, doc file
- Files modified — diagnostics.ts, rules/index.ts, src/index.ts, README.md
- Test results — number of valid and invalid cases, all passing
- Changeset — package, bump type (), summary line
Quick Reference: Key Files
| Purpose | Path |
|---|
| Rule implementation | packages/eslint-plugin-fiori-tools/src/rules/sap-[name].ts
|
| Rule registry | packages/eslint-plugin-fiori-tools/src/rules/index.ts
|
| Plugin config & exports | packages/eslint-plugin-fiori-tools/src/index.ts
|
| Diagnostic constants | packages/eslint-plugin-fiori-tools/src/language/diagnostics.ts
|
| Annotation helper utilities | packages/eslint-plugin-fiori-tools/src/project-context/linker/annotations.ts
|
| Annotation index key format | packages/eslint-plugin-fiori-tools/src/project-context/parser/service.ts
(lines 50-57) |
| Linker types | packages/eslint-plugin-fiori-tools/src/project-context/linker/types.ts
|
| V2 linker | packages/eslint-plugin-fiori-tools/src/project-context/linker/fe-v2.ts
|
| V4 linker | packages/eslint-plugin-fiori-tools/src/project-context/linker/fe-v4.ts
|
| Rule factory | packages/eslint-plugin-fiori-tools/src/language/rule-factory.ts
|
| Rule fixer | packages/eslint-plugin-fiori-tools/src/language/rule-fixer.ts
|
| Test helper | packages/eslint-plugin-fiori-tools/test/test-helper.ts
|
| Rule docs template | packages/eslint-plugin-fiori-tools/docs/rules/TEMPLATE.md
|
| README rules table | packages/eslint-plugin-fiori-tools/README.md
|
context access by rule type
| Rule type | Use in | Why |
|---|
| Annotation | for page iteration; for getIndexedServiceForMainService
| Only check annotations referenced from pages — never scan all entity annotations. must list only pages that reference the specific annotation. See for access patterns and the page-annotation-map template. |
| Manifest JSON | for page iteration; for (manifest URI, manifestObject) | Requires linked pages to find manifest config paths |
| Flex change | context.sourceCode.projectContext.linkedModel.apps
| Guard on first; linked model provides change file config via |
| JavaScript / TypeScript | Standard ESLint — no | JS/TS rules don't use the Fiori project model; use , not |