Skip to content

Commit b8c05d2

Browse files
Add module-specific CLAUDE.md files for Python and JavaScript (#6886)
* Add module-specific CLAUDE.md files for Python and JavaScript The root CLAUDE.md covers the full monorepo from a Java-centric perspective. The Python and TypeScript modules have their own build systems, test runners, and conventions that are separate from the Java side. - Add rewrite-python/rewrite/CLAUDE.md with Python-specific setup, test commands, directory structure, and development patterns - Add rewrite-javascript/rewrite/CLAUDE.md with Node.js setup, async visitor patterns, test patterns, and RPC conventions - Update root CLAUDE.md to cross-reference module files instead of duplicating TypeScript guidelines inline - Fix ADR path (docs/adr/ → doc/adr/) and add missing modules (rewrite-csharp, rewrite-docker, rewrite-java-25) * Trim module CLAUDE.md files for conciseness Remove content that duplicates the directory structure, lists fragile recipe names, or restates things obvious from file/function names.
1 parent 4d9aa37 commit b8c05d2

3 files changed

Lines changed: 387 additions & 51 deletions

File tree

CLAUDE.md

Lines changed: 16 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
66

77
When you need to know something about OpenRewrite:
88
- Refer to the rewrite-docs folder (if available)
9-
- Consult Architecture Decision Records in `docs/adr/` for design decisions
9+
- Consult Architecture Decision Records in `doc/adr/` for design decisions
1010

1111
## Project Overview
1212

@@ -100,17 +100,12 @@ OpenRewrite is an automated refactoring ecosystem for source code that eliminate
100100
./gradlew test --tests "*Maven*"
101101
```
102102

103-
### JavaScript Module (rewrite-javascript)
104-
```bash
105-
# Install Node.js dependencies
106-
./gradlew :rewrite-javascript:npmInstall
107-
108-
# Run JavaScript tests
109-
./gradlew :rewrite-javascript:npm_test
103+
### Python and JavaScript Modules
104+
For detailed build and test instructions specific to the Python (`rewrite-python/rewrite/`) and JavaScript (`rewrite-javascript/rewrite/`) modules, refer to their respective `CLAUDE.md` files:
105+
- `rewrite-python/rewrite/CLAUDE.md` — Python module setup, testing, and recipes
106+
- `rewrite-javascript/rewrite/CLAUDE.md` — TypeScript/JavaScript module setup, testing, and recipes
110107

111-
# Build JavaScript components
112-
./gradlew :rewrite-javascript:npm_run_build
113-
```
108+
These modules use their own package managers (`uv`/`pip` for Python, `npm` for Node.js) and are separate from the Java Gradle build.
114109

115110
## Project Structure
116111

@@ -120,8 +115,9 @@ OpenRewrite is an automated refactoring ecosystem for source code that eliminate
120115

121116
### Language Parsers
122117
- **`rewrite-java`**: Main Java language support with comprehensive AST model
123-
- **`rewrite-java-8/11/17/21`**: Java version-specific features and compatibility
124-
- **`rewrite-groovy/kotlin/javascript`**: Other JVM and web languages extending the `J` model from `rewrite-java`
118+
- **`rewrite-java-8/11/17/21/25`**: Java version-specific features and compatibility
119+
- **`rewrite-groovy/kotlin/javascript/csharp`**: Other languages extending the `J` model from `rewrite-java`
120+
- **`rewrite-docker`**: Dockerfile parsing and manipulation
125121

126122
### Format Parsers
127123
- **`rewrite-maven`**: Maven POM manipulation and dependency management
@@ -136,7 +132,7 @@ OpenRewrite is an automated refactoring ecosystem for source code that eliminate
136132

137133
## Architecture Decision Records (ADRs)
138134

139-
Significant architectural decisions are documented in `docs/adr/`. When working on features that involve architectural decisions, consult existing ADRs and create new ones as needed following the standard ADR format (Context, Decision, Consequences).
135+
Significant architectural decisions are documented in `doc/adr/`. When working on features that involve architectural decisions, consult existing ADRs and create new ones as needed following the standard ADR format (Context, Decision, Consequences).
140136

141137
## Development Patterns
142138

@@ -210,45 +206,14 @@ The build enforces license headers on all source files and runs OWASP dependency
210206
- Use appropriate data structures for the task
211207
- Follow the principle of least surprise
212208

213-
## TypeScript Guidelines
214-
215-
### Organization
216-
- The Node project root for the TypeScript code is `rewrite-javascript/rewrite`. So when running `npm`, make sure to add `--prefix rewrite-javascript/rewrite` to the command or change into that directory before running the command.
217-
- The TypeScript code represents an implementation of OpenRewrite Java in TypeScript
218-
- The modules directly inside `src`, `src/rpc`, `src/text` roughly correspond to the repo-level Gradle project `rewrite-core`
219-
- The modules in `src/java` correspond to the Java code in the Gradle project `rewrite-java`
220-
- The modules in `src/javascript` correspond to the Java code in the Gradle project `rewrite-javascript`
221-
- The modules in `src/json` correspond to the Java code in the Gradle project `rewrite-json`
222-
- The modules in `src/test` correspond to the Java code in the Gradle project `rewrite-test`
223-
- Specifically, there are a lot of types which have the exact same names and structures in both the Java and the TypeScript code (e.g. `JavaVisitor` or `Markers`).
224-
- A lot of types (specifically those in `tree.ts` and `markers.ts` files) represent data types which need to have matching definitions in Java and TypeScript to support a custom serialization mechanism
225-
- The serialization mechanism is generally referred to as RPC and implemented in `src/rpc` (and inside the Java package `org.openrewrite.rpc` of `rewrite-core`)
226-
- Further, the serialization mechanism is visitor-based and thus for each of the supported languages there is a "sender" and a "receiver" (e.g. `JavaSender` and `JavaReceiver`) which each needs an implementation in both Java and TypeScript and at the same time this must be fully aligned with the corresponding model (e.g. `src/java/tree.ts`)
209+
## Language-Specific Guidelines
227210

228-
### Code Style
229-
- Follow standard TypeScript naming conventions
230-
- Classes and interfaces: PascalCase
231-
- Methods, properties, and variables: camelCase
232-
- Constants: UPPER_SNAKE_CASE
233-
- Use 4 spaces for indentation
234-
- Keep lines under 120 characters
235-
- Use meaningful variable and method names
211+
For detailed guidance on working with specific language implementations, consult the module-specific CLAUDE.md files:
212+
213+
- **Python (`rewrite-python/rewrite/CLAUDE.md`)**: Development setup, testing with RPC, recipe patterns, padding/whitespace conventions specific to the Python module.
214+
- **TypeScript/JavaScript (`rewrite-javascript/rewrite/CLAUDE.md`)**: Node.js setup, async visitor patterns, test patterns, RPC sender/receiver architecture, module organization.
236215

237-
### TypeScript Patterns
238-
- Use TypeScript interfaces and classes for type safety
239-
- Use generics for reusable code
240-
- Use async/await for asynchronous operations (including the visitor which is async)
241-
- Use Immer for immutable state management
242-
- Use the visitor pattern for tree traversal and transformation
243-
- Use optional chaining for null/undefined handling
244-
245-
### TypeScript Best Practices
246-
- Explicitly type function parameters and return values
247-
- Use readonly for immutable properties
248-
- Use union types instead of inheritance where appropriate
249-
- Avoid any type where possible
250-
- Use type guards for runtime type checking
251-
- Use async/await instead of raw promises
216+
These files contain implementation-specific patterns, conventions, and debugging tips that supersede general guidance in this document.
252217

253218
## Version Control Guidelines
254219

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code when working with the OpenRewrite TypeScript implementation.
4+
5+
## Module Overview
6+
7+
TypeScript implementation of OpenRewrite for JavaScript/TypeScript source code transformations, plus JSON and YAML support. Includes parsers, AST models, visitors, printers, and an RPC bridge for Java communication.
8+
9+
Self-contained Node.js project, separate from the Java monorepo build system.
10+
11+
## Project Setup
12+
13+
From `rewrite-javascript/rewrite/`:
14+
```bash
15+
npm install
16+
```
17+
18+
Via Gradle (from repo root):
19+
```bash
20+
./gradlew :rewrite-javascript:npmInstall
21+
./gradlew :rewrite-javascript:npm_test
22+
./gradlew :rewrite-javascript:npm_run_build
23+
```
24+
25+
Requires Node.js 18+.
26+
27+
## Running Tests
28+
29+
```bash
30+
# Full suite (typecheck + build + test)
31+
npm test
32+
33+
# Fast iteration (skip typecheck)
34+
npm run testhelper
35+
36+
# Type-checking only
37+
npm run typecheck
38+
39+
# Individual test file
40+
npm run testhelper -- test/javascript/recipes/order-imports.test.ts
41+
```
42+
43+
Available npm scripts: `prebuild`, `build`, `postbuild`, `typecheck`, `dev`, `test`, `testhelper`, `build:fixtures`, `ci:test`, `start`.
44+
45+
## Directory Structure
46+
47+
```
48+
rewrite-javascript/rewrite/
49+
├── src/
50+
│ ├── index.ts # Main entry point / re-exports
51+
│ ├── tree.ts, visitor.ts, recipe.ts # Core framework
52+
│ ├── markers.ts, execution.ts # Metadata, execution context
53+
│ ├── print.ts, parser.ts # Base printer, base parser
54+
│ ├── util.ts, uuid.ts # Utilities
55+
│ ├── java/ # Java LST model
56+
│ │ ├── tree.ts # J namespace (Java AST)
57+
│ │ ├── visitor.ts # JavaVisitor
58+
│ │ ├── print.ts # Java-to-source printer
59+
│ │ ├── rpc.ts # RPC sender/receiver for Java
60+
│ │ └── type.ts, type-visitor.ts # Java type system
61+
│ ├── javascript/ # JavaScript/TypeScript
62+
│ │ ├── tree.ts # JS namespace (JavaScript AST)
63+
│ │ ├── visitor.ts # JavaScriptVisitor
64+
│ │ ├── print.ts # JS-to-source printer
65+
│ │ ├── parser.ts # JS/TS parser
66+
│ │ ├── rpc.ts # RPC sender/receiver for JS
67+
│ │ ├── assertions.ts # Test helpers: typescript(), javascript(), jsx(), tsx(), packageJson()
68+
│ │ ├── add-import.ts, remove-import.ts # Import manipulation
69+
│ │ ├── recipes/ # Built-in recipes (order-imports, change-import, add-dependency, etc.)
70+
│ │ ├── format/ # Formatting visitors
71+
│ │ ├── cleanup/ # Cleanup recipes (add-parse-int-radix, prefer-optional-chain, etc.)
72+
│ │ ├── migrate/ # Migration recipes (es6/, typescript/)
73+
│ │ ├── search/ # Search patterns
74+
│ │ └── templating/ # Template engine
75+
│ ├── json/ # JSON support (tree, visitor, print, rpc, recipes)
76+
│ ├── yaml/ # YAML support (tree, visitor, print, rpc, recipes)
77+
│ ├── search/ # Cross-language search utilities
78+
│ ├── text/ # Plain text support
79+
│ ├── rpc/ # RPC infrastructure
80+
│ │ ├── queue.ts # Message queue
81+
│ │ ├── rewrite-rpc.ts # Core RPC protocol
82+
│ │ ├── server.ts # RPC server
83+
│ │ ├── recipe.ts # Recipe RPC bridge
84+
│ │ ├── trace.ts # RPC tracing/debugging
85+
│ │ └── request/ # Request types (parse, visit, get-object, etc.)
86+
│ └── test/ # Testing infrastructure
87+
│ └── rewrite-test.ts # RecipeSpec class, rewriteRun()
88+
├── test/ # Jest tests (mirrors src/ structure)
89+
│ ├── javascript/ # JS/TS tests
90+
│ │ ├── recipes/ # Recipe tests
91+
│ │ ├── fixtures/ # Test npm projects
92+
│ │ ├── parser/, format/, cleanup/ # Category tests
93+
│ │ └── search/, templating/, migrate/
94+
│ ├── java/ # Java model tests
95+
│ ├── json/, yaml/ # JSON/YAML tests
96+
│ └── rpc/ # RPC integration tests
97+
├── tsconfig.json
98+
├── jest.config.js
99+
└── package.json # name: @openrewrite/rewrite
100+
```
101+
102+
## Development Patterns
103+
104+
### Async Visitor Pattern
105+
106+
**All visitor methods are async.** This supports the RPC nature of the framework.
107+
108+
```typescript
109+
export class MyVisitor extends JavaScriptVisitor<ExecutionContext> {
110+
protected async visitJsCompilationUnit(
111+
cu: JS.CompilationUnit,
112+
p: ExecutionContext
113+
): Promise<JS.CompilationUnit> {
114+
// Transform and return
115+
return cu;
116+
}
117+
}
118+
```
119+
120+
Hierarchy: `TreeVisitor``JavaVisitor``JavaScriptVisitor`
121+
122+
### Immutability and Structural Sharing
123+
124+
LST nodes are immutable. Use `updateIfChanged()` for single-field updates:
125+
126+
```typescript
127+
const updated = updateIfChanged(node, 'field', newValue);
128+
```
129+
130+
For multiple updates, use `produceAsync()` (Mutative-based draft mutations):
131+
```typescript
132+
import { produceAsync } from '../../visitor';
133+
134+
const updated = await produceAsync(cu, async draft => {
135+
draft.statements = newStatements;
136+
});
137+
```
138+
139+
Note: The project uses [Mutative](https://github.com/unadlib/mutative) (not Immer) for immutable state management.
140+
141+
### RPC Kind Constants
142+
143+
LST nodes have a `kind` property that must exactly match Java FQN strings:
144+
145+
```typescript
146+
// These must stay in sync with Java — any mismatch breaks RPC serialization
147+
CompilationUnit: "org.openrewrite.javascript.tree.JS$CompilationUnit"
148+
```
149+
150+
## Recipe Pattern
151+
152+
```typescript
153+
import { Recipe, ExecutionContext, TreeVisitor } from '../../';
154+
import { JavaScriptVisitor } from '../visitor';
155+
import { JS } from '../tree';
156+
157+
export class MyRecipe extends Recipe {
158+
readonly name = 'org.openrewrite.javascript.MyRecipe';
159+
readonly displayName = 'My Recipe';
160+
readonly description = 'Describes what this recipe does';
161+
162+
async editor(): Promise<TreeVisitor<any, ExecutionContext>> {
163+
return new class extends JavaScriptVisitor<ExecutionContext> {
164+
protected async visitJsCompilationUnit(cu: JS.CompilationUnit, p: ExecutionContext) {
165+
return cu;
166+
}
167+
};
168+
}
169+
}
170+
```
171+
172+
## Test Pattern
173+
174+
Tests use relative imports. Source spec factories (`typescript()`, `javascript()`, `jsx()`, `tsx()`, `packageJson()`) are in `src/javascript/assertions.ts`.
175+
176+
```typescript
177+
import { RecipeSpec } from "../../../src/test";
178+
import { typescript } from "../../../src/javascript";
179+
import { OrderImports } from "../../../src/javascript/recipes/order-imports";
180+
181+
describe('OrderImports', () => {
182+
test('sorts imports', () =>
183+
new RecipeSpec({ recipe: new OrderImports() }).rewriteRun(
184+
typescript(
185+
`import {z} from 'zebra';\nimport {a} from 'alpha';`,
186+
`import {a} from 'alpha';\nimport {z} from 'zebra';`
187+
)
188+
)
189+
);
190+
});
191+
```
192+
193+
## RPC Sender/Receiver
194+
195+
Each language module has `rpc.ts` with a Sender (visit tree → serialize to queue) and Receiver (read queue → reconstruct tree). These must stay aligned with each other AND with the Java equivalents. Any mismatch causes deadlocks or corrupted trees.
196+
197+
## Debugging Tips
198+
199+
### RPC Hangs
200+
1. Check that both Java and TypeScript RPC methods are implemented
201+
2. Verify Kind constants match between Java and TypeScript
202+
3. Run with `--detectOpenHandles` to find unclosed promises: `npm run testhelper -- --detectOpenHandles`
203+
4. Check `src/rpc/queue.ts` for deadlock in read/write operations
204+
205+
### Type Checking
206+
Run `npm run typecheck` frequently to catch type mismatches early.

0 commit comments

Comments
 (0)