Skip to content

Commit 26efbdb

Browse files
committed
auto-bootstrap AGENTS.md with GH copilot + Sonnet 4.5
1 parent 9af410d commit 26efbdb

File tree

1 file changed

+154
-0
lines changed

1 file changed

+154
-0
lines changed

AGENTS.md

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
# Scalafix AI Coding Agent Instructions
2+
3+
## Project Overview
4+
5+
Scalafix is a refactoring and linting tool for Scala. It enables syntactic and semantic source code transformations through a rule-based system. The project targets multiple Scala versions (2.12, 2.13, 3.3-3.7) and is built using a complex sbt-projectmatrix setup.
6+
7+
**Core Architecture:**
8+
- `scalafix-interfaces`: Java API for JVM integration (cross-platform, no Scala dependency)
9+
- `scalafix-core`: Data structures for AST rewriting and linting (Scala 2.12/2.13)
10+
- `scalafix-rules`: Built-in rules like `RemoveUnused`, `ProcedureSyntax` (cross-compiled for all Scala versions)
11+
- `scalafix-reflect`: Runtime rule compilation (Scala 2 only)
12+
- `scalafix-cli`: Command-line interface (cross-compiled for all Scala versions)
13+
- `scalafix-testkit`: Testing framework for rules using input/output file pairs
14+
15+
## Critical Build Architecture
16+
17+
### sbt-projectmatrix Cross-Building
18+
The build uses `sbt-projectmatrix` to generate multiple sub-projects per module, cross-compiled against different Scala versions. This is NOT standard Scala cross-building.
19+
20+
**TargetAxis System**: Custom mechanism in `project/TargetAxis.scala` that creates test matrix combinations:
21+
- Each test project is built with a specific Scala version (the "target")
22+
- Test frameworks compiled with another Scala version can test against that target
23+
- Some targets include `-Xsource:3` flag (tagged with `Xsource3Axis`)
24+
- Example: `expect3_3_6Target3_3_6` tests rules compiled with 3.3.6 against input also compiled with 3.3.6
25+
26+
**Key build concepts:**
27+
- `projectMatrix`: Defines modules that cross-compile
28+
- `.jvmPlatform(scalaVersions)`: Creates one sub-project per Scala version
29+
- `.jvmPlatformTargets(targets)`: Creates sub-projects for test targets
30+
- `.jvmPlatformAgainstTargets(tuples)`: Creates test projects that run with one Scala version against target compiled with another
31+
- Use `resolve(matrix, key)` to lookup and extract settings from the matching sub-project
32+
33+
## Development Workflows
34+
35+
### Running Tests
36+
```bash
37+
# Unit tests for latest Scala 3.3.6 version
38+
sbt "unit3_3_6 / test"
39+
40+
# Integration tests (contains many suites - use testOnly to narrow)
41+
sbt "integration3_3_6 / testOnly -- -z ProcedureSyntax"
42+
43+
# Test built-in rules using scalafix-testkit
44+
sbt "expect3_3_6Target3_3_6 / test"
45+
46+
# Windows-compatible tests only
47+
sbt "unit3_3_6 / testWindows"
48+
```
49+
50+
**Pattern**: Test project names combine the Scala version used to compile the test framework with the target being tested: `unit{CompilerVersion}` or `expect{CompilerVersion}Target{TargetVersion}`
51+
52+
### Applying Scalafix to Itself (Dogfooding)
53+
```bash
54+
# First, publish local artifacts for all Scala versions
55+
sbt "dogfoodScalafixInterfaces; scalafixAll"
56+
```
57+
58+
The `dogfoodScalafixInterfaces` command:
59+
1. Runs `publishLocalTransitive` on all CLI versions
60+
2. Reloads sbt plugins
61+
3. Overrides `scalafix-interfaces` version in meta-build
62+
4. Returns to main build
63+
64+
### Formatting
65+
```bash
66+
# Format all files
67+
./bin/scalafmt
68+
69+
# Format only changed files
70+
./bin/scalafmt --diff
71+
```
72+
73+
### Documentation
74+
```bash
75+
# Generate docs with mdoc and start Docusaurus server
76+
sbt ci-docs
77+
cd website && yarn start
78+
```
79+
80+
## Rule Development Patterns
81+
82+
### Rule Types
83+
- **SyntacticRule**: Works with AST only, no semantic information (fast)
84+
- Example: `ProcedureSyntax` - replaces `def foo { }` with `def foo: Unit = { }`
85+
- **SemanticRule**: Requires SemanticDB (compiler symbols, types)
86+
- Example: `RemoveUnused` - removes imports/terms flagged by `-Wunused`
87+
- Requires `-Wunused`, `-Ywarn-unused`, or `-Wall` compiler flag
88+
89+
### Creating Rules
90+
Rules extend `scalafix.v1.Rule` and must:
91+
1. Define in `scalafix-rules/src/main/scala/scalafix/internal/rule/`
92+
2. Register in `src/main/resources/META-INF/services/scalafix.v1.Rule`
93+
3. Return `Patch` operations (not string diffs)
94+
4. Use `.atomic` on patches for suppression support
95+
96+
**Key APIs:**
97+
- `Patch.addLeft(tree, string)` / `Patch.addRight(tree, string)`: Insert text
98+
- `Patch.removeToken(token)`: Delete token
99+
- `Patch.replaceTree(tree, string)`: Replace tree node
100+
- `tree.symbol`: Get symbol from tree (requires `SemanticDocument`)
101+
- `SymbolMatcher`: Pattern match symbols like `val HasOption = SymbolMatcher.normalized("scala/Option#")`
102+
- `tree.collect { case ... }`: Traverse AST
103+
104+
### Testing Rules with Testkit
105+
Test structure in `scalafix-tests/`:
106+
- `input/`: Source files to transform (with special comments for assertions)
107+
- `output/`: Expected output after rewrite
108+
- `expect/`: Test suite that compares input→output transformation
109+
110+
Special comment syntax in input files:
111+
```scala
112+
/* rules = MyRule */ // Configure which rules to run
113+
import Unused // assert: UnusedImport (linter assertion)
114+
```
115+
116+
## Project-Specific Conventions
117+
118+
### Cross-Version Compatibility
119+
- Use `CrossVersion.for3Use2_13` for Scala 3 depending on Scala 2.13 artifacts
120+
- Scala 3 rules depend on Scala 2.13 compiled `scalafix-core` (no native Scala 3 core yet)
121+
- Use `semanticdbScalacCore.cross(CrossVersion.full)` for compiler plugins
122+
123+
### Module Dependencies
124+
- `rules` depends on `core` (rewriting primitives)
125+
- `cli` depends on `rules` + `reflect` (to load external rules)
126+
- `testkit` depends on `cli` (full execution environment)
127+
- `reflect` only exists for Scala 2 (no Scala 3 version)
128+
129+
### Binary Compatibility
130+
- Use `sbt versionPolicyCheck` before releasing
131+
- `scalafix.internal._` packages have no compatibility guarantees
132+
- Public API in `scalafix.v1` follows Early SemVer
133+
134+
### Configuration Files
135+
- `.scalafix.conf`: Rules applied when dogfooding (uses HOCON format)
136+
- Rules configured via `withConfiguration()` method
137+
- Test files use `/* rules = ... */` comments for configuration
138+
139+
## Common Pitfalls
140+
141+
1. **Wrong test scope**: Use `unit3_3_6 / test` not `test` (ambiguous without projectmatrix context)
142+
2. **Missing BuildInfo**: IntelliJ debugger requires running `sbt "unit3_3_6 / test"` once to generate BuildInfo
143+
3. **Scala 3 reflect**: No `reflect3` module - Scala 3 rules can't dynamically compile
144+
4. **Dependency resolution**: When bumping Scala versions, update `versionPolicyIgnored` in `ScalafixBuild.scala`
145+
5. **Test failures on Windows**: Use `testWindows` task, not `test`
146+
147+
## Key Files to Reference
148+
149+
- `project/TargetAxis.scala`: Understand test matrix cross-building
150+
- `project/ScalafixBuild.scala`: Custom sbt settings and commands
151+
- `project/Dependencies.scala`: Scala version constants
152+
- `scalafix-core/src/main/scala/scalafix/v1/Rule.scala`: Rule base classes
153+
- `scalafix-testkit/src/main/scala/scalafix/testkit/SemanticRuleSuite.scala`: Test framework
154+
- `docs/developers/tutorial.md`: Step-by-step rule creation guide

0 commit comments

Comments
 (0)