Airframe Scala Development
Expert guide for developing the wvlet/airframe project - a multi-module Scala build system supporting JVM, Scala.js, and Scala Native platforms with strict dependency management and cross-platform compatibility.
Tech Stack
**Primary Languages**: Scala, Scala.js, Scala Native**Scala Versions**: Prioritize Scala 2.13 syntax for broad compatibility; Scala 2.12 compatible syntax is acceptable**Scala 3**: Use Scala 3 specific syntax **only** within `src/{main,test}/scala3` directories**Build Tool**: sbt (Scala Build Tool)**Testing Framework**: AirSpecProject Structure
This is a multi-module sbt project where most modules are cross-built for JVM, JS, and Native platforms.
Platform-Specific Code Locations
**JVM**: `.jvm/src/main/scala`, `.jvm/src/test/scala`**JS**: `.js/src/main/scala`, `.js/src/test/scala`**Native**: `.native/src/main/scala`, `.native/src/test/scala`**Shared code** (common to all platforms): `src/main/scala` and `src/test/scala`Dependency Management
**airframe-core module**: Designed for minimal dependencies. Avoid adding new library dependencies unless absolutely necessary**Other modules**: Carefully consider the impact of adding new dependenciesCheck `libraryDependencies` in `build.sbt` for each module to understand current dependenciesWhen adding dependencies: - Ensure availability for all relevant platforms (JVM, JS, Native) if the module is cross-built
- Prefer libraries already used in other modules for similar functionality
- For `airframe-core`, new dependencies are highly discouraged
Coding Style
Code Formatting
Before committing changes, run:
```bash
./sbt scalafmtAll
```
For targeted formatting of specific modules:
```bash
./sbt "(moduleNameJVM)/scalafmtAll"
```
Style Guidelines
**Case classes for configuration**: Must have `withXXX(...)` methods for all fields and `noXXX(...)` methods for all optional fields**String interpolation**: Always enclose expressions with brackets: `${...}` for consistency**Error handling**: Returning `Try[A]` is generally discouraged as it forces a monadic style on the caller. Consider using plain exceptions for unrecoverable errors, or domain-specific error typesTesting
Compilation
Open sbt shell:
```bash
./sbt
```
Compile source and test code by platform:
```bash
./sbt projectJVM/Test/compile # JVM projects
./sbt projectJS/Test/compile # JS projects
./sbt projectNative/Test/compile # Native projects
```
Running Tests
Run a specific test class:
```bash
./sbt '(moduleName)(JVM|JS|Native)/testOnly *TestClassName'
```
Examples:
```bash
JVM test in airframe-log module
./sbt 'logJVM/testOnly *MyLogTest'
JS test in airframe-codec module
./sbt 'codecJS/testOnly fully.qualified.TestClassName'
```
Testing Best Practices
Use AirSpec testing frameworkKey assertion syntaxes: `shouldBe`, `shouldNotBe`, `shouldMatch`Test names should be concise and descriptive, written in plain EnglishAvoid using mocks as they increase maintenance costEnsure tests cover new functionality and bug fixesAim for good test coverageWhen tests fail, carefully analyze stack trace and assertion failures from sbt outputGit Workflow
Branch Naming
Create new branches with timestamp prefix:
```bash
git switch -c feature/$(date +"%Y%m%d_%H%M%S")-your-feature-description
```
Adapt for other change types:
```bash
git switch -c fix/$(date +"%Y%m%d_%H%M%S")-correct-off-by-one-error
git switch -c doc/$(date +"%Y%m%d_%H%M%S")-update-readme
git switch -c internal/$(date +"%Y%m%d_%H%M%S")-refactor-parser
```
Commit Messages
Format: `<type>: <description>`
**feature**: New features (e.g., `feature: Add XXX to improve user experience`)**fix**: Bug fixes**internal**: Non-user facing changes**doc**: Documentation updatesFocus on **why** the change was made, not **what** or **how**.
Pull Requests
Use GitHub CLI for PR operations:
```bash
gh pr create
```
Provide clear title and detailed bodyLink to relevant issuesFollow `.github/pull_request_template.md` formatMerge with squash commits for clean history:```bash
gh pr merge --squash --auto
```
Platform Considerations
When developing cross-platform modules:
Test on all target platforms (JVM, JS, Native)Be aware of platform-specific limitationsUse shared source directories for common codePlace platform-specific implementations in respective directoriesEnsure dependencies are available for all target platforms