This document provides essential guidelines for AI-powered tools working with the SAP UX Tools monorepo. Following these guidelines ensures code quality, maintainability, and consistency across the project.
- Overview
- Critical Requirements
- Quality Gates
- Development Standards
- Package Management
- Testing Requirements
- Security and Maintenance
- Change Management
- Useful Commands
The SAP UX Tools is a monorepo for building SAP Fiori applications. All packages of this monorepo can be found in the /packages folder. The project uses:
- Package Manager: pnpm (see root package.json for required version)
- Node Version: >=20.x (see root package.json engines field)
- Build System: Nx for orchestration
- Testing: Jest for unit tests, Playwright for integration tests
- Versioning: Changesets for automated version management
- Publishing: Automated via GitHub Actions to npmjs.com
Before submitting any changes, ensure all the following commands complete successfully:
pnpm install
pnpm build
pnpm lint
pnpm testIMPORTANT: All four commands must pass without errors. This is non-negotiable for all contributions.
All packages across the pnpm workspace must use the same version of shared dependencies. This ensures consistency and prevents version conflicts.
Check version alignment:
pnpm lint:dependency-versionsThis uses check-dependency-version-consistency to validate that all packages use identical versions of shared dependencies.
Common shared dependencies to align:
- TypeScript
- Jest and testing utilities
- ESLint and related plugins
- Build tools (esbuild, rimraf, etc.)
- UI libraries (React, React-DOM)
Rule: When updating a dependency in one package, update it in ALL packages that use it.
Exception — peerDependencies must keep open semver ranges:
peerDependencies declare compatibility with a host package the consumer provides. They must use open caret (^) or tilde (~) ranges, never exact (pinned) versions. Pinning a peerDependency forces every consumer to install that exact version, which breaks the moment they upgrade and defeats the purpose of peer ranges.
Guidelines:
- Use
^major(e.g.,^9) when the package works across the entire major version - Use
^major.minor(e.g.,^8.57.2) when a minimum minor/patch is required for a specific API - Never pin to an exact version — consumers must be free to use any compatible release
- The corresponding
devDependenciesentry (used for testing) can be pinned to a specific version; only thepeerDependenciesentry must stay open - When bumping a peerDependency range (e.g.,
^8→^9), this is a breaking change and requires a major version bump of the package
Real example (@sap-ux/eslint-plugin-fiori-tools):
"devDependencies": {
"eslint": "9.39.1" // pinned for reproducible test runs — OK
},
"peerDependencies": {
"eslint": "^9" // open range for consumers — required
}Dependencies should not be older than 6 months to ensure security, bug fixes, and compatibility with the ecosystem.
Guidelines:
- Regularly review and update dependencies
- Check npm registry for latest stable versions
- Review changelogs for breaking changes before upgrading
- Test thoroughly after version bumps
- Use
pnpm overrides(in root package.json) for security patches when necessary
Check dependency ages:
# Check outdated dependencies
pnpm outdated
# Check specific package
pnpm outdated --filter @sap-ux/[package-name]Minimum code coverage: 80% for all code changes and packages
Requirements:
- All new code must include comprehensive tests
- Modified code must maintain or improve existing coverage
- Coverage is measured on the
src/**/*.tsfiles - Both unit tests and integration tests contribute to coverage
Check coverage:
# Run tests with coverage
pnpm test
# View coverage reports
# Coverage reports are in: packages/[package-name]/coverage/lcov-report/index.htmlCoverage Configuration (from jest.base.js):
collectCoverageFrom: ['src/**/*.ts']- Reports: text and lcov formats
- SonarCloud integration via jest-sonar reporter
All lint errors must be fixed before committing code.
Run linting:
# Check for lint errors
pnpm lint
# Auto-fix lint issues
pnpm lint:fixLinting covers:
- TypeScript code style (ESLint with typescript-eslint)
- Code formatting (Prettier integration)
- Import ordering and resolution
- JSDoc documentation requirements
- Promise handling best practices
- Security patterns (via eslint-plugin-sonarjs)
Configuration:
- Root config: eslint.config.js
- Prettier config: .prettierrc.js
pnpm audit issues should be resolved promptly.
Check for vulnerabilities:
pnpm auditResolution strategies:
- Update vulnerable packages to patched versions
- Use pnpm overrides for transitive dependencies (see root package.json)
- Document exceptions if updates break functionality
- Prioritize high and critical vulnerabilities
Existing overrides (from package.json):
- axios, esbuild, fast-xml-parser, lodash, tar (security patches)
- Review and update these regularly
All code should be written in modern TypeScript.
Standards:
- TypeScript 5.9.3+ (current version in repo)
- Target: ES2023
- Strict mode enabled
- Use ES modules (import/export)
- Prefer
constoverlet - Use async/await over raw Promises
- Leverage TypeScript features: generics, union types, type guards, etc.
- Avoid
anytype - useunknownor proper types - Avoid TypeScript enums - prefer union types or const objects for better type safety and tree-shaking
TypeScript config (from tsconfig.json):
- Strict mode enabled
- Composite projects for incremental builds
- Project references for monorepo structure
Package naming rules:
-
All packages must include
@sap-uxscope UNLESS:- It is a VSCode extension (e.g.,
sap-ux-sap-systems-ext) - It is marked as publisher = "SAPOSS",
- It is a VSCode extension (e.g.,
-
Folder structure:
- Package folders:
packages/[name] - Folder name = package name without
@sap-ux/prefix - Example:
@sap-ux/fiori-freestyle-writer→packages/fiori-freestyle-writer
- Package folders:
-
Extension naming:
- Pattern:
sap-ux-[name]-ext - Examples:
sap-ux-application-modeler-ext,sap-ux-sap-systems-ext
- Pattern:
-
Private packages:
- Packages intended for internal use only (e.g., test utilities, integration tests) must have
"private": truein package.json - Private packages are NOT published to npm
- Use
@sap-ux-private/scope for private packages - Example:
@sap-ux-private/adaptation-editor-tests - Default: All packages are public unless explicitly marked private - only add
"private": truewhen the package should not be published
- Packages intended for internal use only (e.g., test utilities, integration tests) must have
All changes to source code or runtime dependencies require a changeset.
When to create a changeset:
- ✅ Any changes to files in
src/directory - ✅ Adding, removing, or updating runtime
dependenciesinpackage.json(version bumps, additions, or removals) - ✅ Changes to templates or runtime assets
- ✅ Bug fixes
- ✅ New features
- ✅ Breaking changes
- ✅ Changes to README.md
- ✅ Formatting or lint autofix changes to
src/files (even if purely cosmetic, they touch published source) - ✅ Private packages (
"private": true) — they still need changesets even though they are not published to npm. Changesets drive internal versioning and CHANGELOG generation.
When NOT to create a changeset:
- ❌ Changes only to tests (test files in
test/directories) - ❌ Changes only to
devDependencies(unless the package uses esbuild for bundling, as bundled devDependencies affect runtime) - ❌ Configuration changes (eslint, prettier, jest configs) that don't touch
src/ - ❌ CI/CD pipeline updates (.github/workflows)
Private packages and changesets:
Packages with "private": true in their package.json are NOT published to npm, but they still require changesets when their source code or runtime dependencies change. Use the package's exact name field from its package.json in the changeset frontmatter — for example:
---
"@sap-ux-private/preview-middleware-client": patch
---
chore(preview-middleware-client): upgrade shared devDependencies (jest 30)To identify private packages in the repo:
# List all private packages
grep -l '"private": true' packages/*/package.json | xargs -I{} node -e "const p=require('{}');console.log(p.name)"How to identify which packages need a changeset:
When reviewing a branch or PR, check both source code and dependency changes — it is a common mistake to only check src/ files and miss runtime dependency bumps in package.json:
- Source code changes — files in
src/ortemplates/:git diff main HEAD -- 'packages/*/src/' 'packages/*/templates/' | grep '^diff --git' | sed 's|^diff --git a/packages/\([^/]*\)/.*|\1|' | sort -u
- Runtime dependency changes —
"dependencies"section (not"devDependencies") inpackage.json:# List all packages with package.json changes, then inspect each for runtime dep diffs gh pr diff <PR_NUMBER> --repo SAP/open-ux-tools | grep -B2 -A30 '"dependencies"'
- Cross-reference both lists against existing
.changeset/*.mdfiles to find uncovered packages.
Create a changeset:
pnpm cset
# or
pnpm changesetYou can also create changeset files manually in .changeset/. Use a descriptive filename (e.g., package-name-short-description.md):
---
"@sap-ux/package-name": patch
---
chore(package-name): upgrade i18next 25.8.18 → 25.8.20Changeset message conventions:
- Use conventional commit prefixes:
fix,feat,chore, etc. - For dependency-only upgrades:
chore(package-name): upgrade <dep> <old> → <new> - For multiple dep upgrades:
chore(package-name): upgrade runtime dependencies (<dep1> <ver>, <dep2> <ver>) - For formatting/lint autofixes:
chore(package-name): reformat <description> (Prettier upgrade autofix) - For type compatibility fixes:
fix(package-name): <description> for <@types/package> <version> compatibility
Changeset workflow:
- Interactive CLI prompts for:
- Which packages changed
- Version bump type (major/minor/patch)
- Summary of changes
- Creates a markdown file in
.changeset/directory - Commit the changeset file with your changes
- CI validates changesets before merge
- After merge to main, versions are automatically bumped and published
Validation:
The build process includes pnpm validate:changesets to check:
- Changesets have valid frontmatter
- No blocked major version bumps (see scripts/validate-changesets.js)
The CI/CD pipeline enforces these quality gates on all pull requests:
- Build: All packages must build successfully
- Lint: Code must pass ESLint checks (on forks)
- Unit Tests: All unit tests must pass
- Integration Tests: All Playwright tests must pass
- Changeset Validation: Valid changesets if source code changed
- SonarCloud: Code quality and security scanning
CI Configuration: .github/workflows/pipeline.yml
Matrix testing:
- OS: Ubuntu, Windows, macOS
- Node: 20.x, 22.x
- Timeout: 45 minutes
Follow the conventions in docs/Guidelines.md:
TypeScript:
- Use ESLint and Prettier for consistent formatting
- See eslint.config.js for linting rules
- See .prettierrc.js for formatting rules
- Individual packages may have their own eslint configs that extend the root configuration
Testing:
- Use given/when/then pattern
- Test behavior, not implementation
- Test public interfaces with all possible inputs
- Use Jest snapshots for file generation validation
- Cross-platform snapshots: Snapshots must never contain file or folder paths with
/or\to ensure tests run consistently across Linux, Mac, and Windows - Mock dependencies appropriately
- Keep test scope focused
Git Commits:
- Follow Conventional Commits
- Types:
feat,fix,docs,style,refactor,perf,test,chore,revert,WIP - Max 100 characters for commit message
- Use imperative mood: "Add feature" not "Added feature"
Always reuse existing functions from common libraries before implementing new ones.
Common reusable libraries in this monorepo:
@sap-ux/project-access- Project file system operations and Fiori project utilities@sap-ux/axios-extension- Enhanced HTTP client with middleware support@sap-ux/logger- Logging utilities and message handling@sap-ux/ui5-config- UI5 configuration management@sap-ux/store- Secure storage and credentials management@sap-ux/btp-utils- SAP BTP platform utilities- And others in
/packagesfolder
Guidelines:
-
Search before implementing: Before creating a new utility function, search existing common libraries to see if the functionality already exists
# Search for existing functionality pnpm --filter @sap-ux/project-access exec -- echo "Check package API" # Or use grep to search for similar functions
-
Refactor to common libraries: When you find duplicate code across multiple packages:
- Identify the appropriate existing common library to extend
- Or create a new common library if the functionality doesn't fit existing ones
- Move the common function to the shared library
- Update all packages to use the shared implementation
- Ensure proper testing of the refactored code
-
Avoid circular dependencies: When moving code to common libraries:
- Check dependency graphs before refactoring
- Common libraries should depend on other common libraries, not on higher-level packages
- Use the dependency hierarchy: utilities → core libraries → feature packages
- If circular dependencies are unavoidable, consider splitting the library into smaller focused packages
-
Create new common libraries when necessary:
- If functionality doesn't fit existing libraries
- If adding it would create circular dependencies
- Name new libraries following the pattern:
@sap-ux/[descriptive-name] - Keep libraries focused on a single responsibility
- Document the library's purpose and API
-
Document library usage: When using or extending common libraries:
- Update the library's README with new functionality
- Add JSDoc comments for all public APIs
- Include usage examples in documentation
- Update types for TypeScript consumers
User-facing text must be translatable:
- User dialogs and messages
- Button text and labels
- Questions and prompts
Not required for:
- Technical log messages
- Debugging/tracing information
- Exception texts not shown to users
From CONTRIBUTING.md:
- One issue per PR - Keep PRs small and focused
- Follow DCO - Developer Certificate of Origin required
- Code review - Wait for approval before merging
- Don't resolve conversations - Let reviewers mark as resolved
- AI-generated code - Follow SAP's GenAI guidelines
Root: pnpm-workspace.yaml
packages:
- 'packages/*'
- 'examples/*'
- 'tests/integration/*'
- 'tests/fixtures/projects/mock'
- 'types'packages/[package-name]/
├── src/ # Source code (TypeScript)
├── test/ # Unit tests
├── templates/ # Template files (for generators)
├── dist/ # Build output (generated)
├── coverage/ # Test coverage (generated)
├── package.json # Package manifest
├── tsconfig.json # TypeScript config
├── jest.config.js # Jest config
├── eslint.config.js # ESLint config (optional, extends root config)
└── README.md # Package documentation
For internal monorepo packages, use the workspace:* protocol to reference other packages in the workspace:
Example of workspace dependencies in package.json:
{
"dependencies": {
"@sap-ux/logger": "workspace:*",
"@sap-ux/ui5-config": "workspace:*"
}
}This ensures packages always use the local workspace version during development and are replaced with appropriate version ranges during publishing.
Location: test/ or test/unit/ within each package
Naming Convention: Test files follow the pattern *.test.ts, typically matching the source file they test (e.g., logger.ts → logger.test.ts)
Framework: Jest with ts-jest
Base config: jest.base.js
Run tests:
# All packages (run from repository root)
pnpm test
# Specific package - PREFERRED when working on a single package
pnpm --filter @sap-ux/[package-name] test
# or from the package folder
pnpm test
# With coverage
pnpm test # Coverage is collected by defaultIMPORTANT: When working on a specific package, always use pnpm --filter to run only that package's tests. Running pnpm test at the root level tests ALL packages in the monorepo, which is slow and unnecessary for focused development.
Best practices:
- Use
describeblocks to group related tests - Use clear, descriptive test names
- Follow given/when/then structure
- Test edge cases and error conditions
- Use snapshots for generated files
- Mock external dependencies
- Keep tests fast and isolated
Location: test/integration/ or tests/integration/
Framework: Playwright
Run tests:
# All packages
pnpm test:integration
# Specific package
pnpm --filter @sap-ux/[package-name] test:integrationPlaywright setup:
- Browser: Chrome (cached by CI)
- Reports uploaded on failure
- Manual inspection via test output directory
Don't use: Enzyme (deprecated, doesn't support React 17+)
Migration: Issue #833 tracks Enzyme → react-testing-library migration
Environment variables:
UX_DEBUG- Enable debug loggingUX_DEBUG_FULL- Enable verbose debug logging
Regular maintenance:
- Run
pnpm auditweekly - Review and address high/critical vulnerabilities
- Update dependencies quarterly
- Document any exceptions
Located in root package.json:
- Review existing overrides regularly
- Add new overrides for security patches
- Document reason for each override
- Remove obsolete overrides
License: Apache-2.0
REUSE compliance:
- Check:
.github/workflows/reuse-compliance.yml - All files must have proper license headers
- See REUSE specification
Semantic Versioning (semver):
- MAJOR: Breaking changes (incompatible API changes)
- MINOR: New features (backwards compatible)
- PATCH: Bug fixes (backwards compatible)
Config: .changeset/config.json
- Changelog:
@changesets/cli/changelog - Access: public
- Base branch:
origin/main - Internal dependency updates: patch
Automated via GitHub Actions:
- Developer creates changeset with changes
- CI validates changeset on PR
- Merge to main triggers version job
- Version job runs
changeset versionto bump versions - Release job publishes to npmjs.com
- Notifications sent to Slack
- VSCode extensions packaged and released to GitHub
VSCode Extension Release:
- Automatic packaging on version bump
- GitHub release created (draft)
.vsixfile attached to release- Manual approval required for publication
# Install dependencies
pnpm install
# Build all packages
pnpm build
# Force rebuild (skip cache)
pnpm build:force
# Clean build artifacts
pnpm clean# Format code
pnpm format
# Run linting
pnpm lint
# Fix lint issues
pnpm lint:fix
# Check dependency versions
pnpm lint:dependency-versions# Run all tests
pnpm test
# Run integration tests
pnpm test:integration
# Test specific package
pnpm --filter @sap-ux/[package-name] test# Create changeset
pnpm cset
# Validate changesets
pnpm validate:changesets
# Preview version changes
pnpm changeset status# Add dependency to specific package
pnpm --filter @sap-ux/[package-name] add [dependency]
# Run command in specific package
pnpm --filter @sap-ux/[package-name] [command]
# Run command in all packages
pnpm -r [command]# View dependency graph
pnpm graph-deps
# Check workspace structure
pnpm list --depth 0
# View outdated dependencies
pnpm outdated- Contributing Guide: CONTRIBUTING.md
- Development Guidelines: docs/Guidelines.md
- Code of Conduct: docs/CODE_OF_CONDUCT.md
- Version Overrides: docs/version-overrides.md
- Main README: README.md
- CI/CD Pipeline: .github/workflows/pipeline.yml
- ❌ Don't use npm or yarn - Always use pnpm 8.14.0
- ❌ Don't skip tests - All tests must pass before merging
- ❌ Don't forget changesets - Required for all source code changes
- ❌ Don't mix dependency versions - Keep versions aligned across packages
- ❌ Don't commit with lint errors - Always run
pnpm lint:fix - ❌ Don't ignore security audits - Address vulnerabilities promptly
- ❌ Don't skip documentation - Update README and JSDoc as needed
- ❌ Don't break semver - Follow semantic versioning strictly
- ❌ Don't commit generated files - dist/, coverage/, etc. are gitignored
- ❌ Don't reduce code coverage - Maintain or improve 80% threshold
- ❌ Don't duplicate code - Reuse existing functions from common libraries like @sap-ux/project-access, @sap-ux/axios-extension, etc.
- ❌ Don't create circular dependencies - Follow proper dependency hierarchy when refactoring to common libraries
- ❌ Don't run all tests when working on a single package - Use
pnpm --filter @sap-ux/[package-name] testinstead ofpnpm testat root - ❌ Don't hardcode version numbers in documentation - Reference source files (like package.json) instead, as versions change frequently
- ❌ Don't pin peerDependencies to exact versions - Use open semver ranges (e.g.,
^9not9.39.1) so consumers can use any compatible release
Before submitting changes, verify:
-
pnpm installsucceeds -
pnpm buildsucceeds -
pnpm lintpasses with no errors -
pnpm testpasses with ≥80% coverage -
pnpm lint:dependency-versionspasses - Changeset created if source code or runtime dependencies changed
- No pnpm audit vulnerabilities introduced
- Code follows TypeScript and ESLint standards
- Tests follow given/when/then pattern
- Commit messages follow Conventional Commits
- PR is focused on one issue
- Documentation updated if needed
Need Help?
- Open an issue: https://github.com/SAP/open-ux-tools/issues
- Review existing docs: CONTRIBUTING.md, docs/Guidelines.md
- Check recent commits for examples