Skip to content

Commit 345ce3a

Browse files
dbrattliclaude
andcommitted
Add CLAUDE.md and Claude Code project settings
Add CLAUDE.md with build commands, architecture overview, development guidelines, and workflow instructions for Claude Code. Add project-level permission settings to deny reading from irrelevant directories (lib/fcs, fcs-fable, obj, bin, .venv, node_modules, etc.). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent a7b9510 commit 345ce3a

2 files changed

Lines changed: 148 additions & 0 deletions

File tree

.claude/settings.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"permissions": {
3+
"allow": [
4+
"Bash(./build.sh fable-library *)",
5+
"Bash(./build.sh test *)"
6+
],
7+
"deny": [
8+
"Read(lib/fcs/**)",
9+
"Read(src/fcs-fable/**)",
10+
"Read(**/obj/**)",
11+
"Read(**/bin/**)",
12+
"Read(**/.venv/**)",
13+
"Read(**/node_modules/**)",
14+
"Read(src/fable-metadata/lib/**)",
15+
"Read(src/fable-library-ts/lib/**)"
16+
]
17+
}
18+
}

CLAUDE.md

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## Project Overview
6+
7+
Fable is an F# to multi-language compiler that transpiles F# code to JavaScript, TypeScript, Python, Rust, Dart, PHP, and Erlang/BEAM. It uses a fork of F# Compiler Services (FCS) with custom tweaks, located in `lib/fcs`.
8+
9+
## Build Commands
10+
11+
The build system is implemented in F# at `src/Fable.Build/`. All commands go through `build.sh` (or `build.bat` on Windows):
12+
13+
```bash
14+
./build.sh # Show all available commands
15+
16+
# Build runtime libraries
17+
./build.sh fable-library --javascript # Also: --typescript, --python, --dart, --rust, --beam
18+
19+
# Run tests (targets: javascript, typescript, python, dart, rust, beam, integration)
20+
./build.sh test javascript
21+
./build.sh test javascript --watch # Watch mode (recompile on changes)
22+
./build.sh test javascript --skip-fable-library # Skip fable-library rebuild (only if fable-library source is unchanged)
23+
24+
# Python-specific options
25+
./build.sh test python --skip-fable-library-core # Skip slow Rust extension + .pyi rebuild (Python only)
26+
./build.sh test python --type-check # Run Pyright type checking on Python output
27+
28+
# Quick iteration (watch mode on a minimal project)
29+
./build.sh quicktest javascript # Also: typescript, python, dart, rust, beam
30+
```
31+
32+
`--skip-fable-library` is safe when changes are only in `src/Fable.Transforms/` or other compiler code. If you modified runtime library source (e.g., `src/fable-library-py/`, `src/fable-library-ts/`), do not skip. If you already ran `./build.sh fable-library` separately, use `--skip-fable-library` when running tests right afterwards to avoid rebuilding.
33+
34+
Build output goes to `temp/`: transpiled runtime libraries in `temp/fable-library-<target>/` and test output in `temp/tests/<target>/` (e.g., `temp/fable-library-beam/` and `temp/tests/beam/`).
35+
36+
Test runners by target: JavaScript/TypeScript use Mocha, Python uses pytest (with `uv`, not pip), Rust uses cargo test, Dart uses `dart test`.
37+
38+
## Architecture
39+
40+
### Compiler Pipeline
41+
42+
```text
43+
F# Source → FCS Parser → F# AST → FSharp2Fable → Fable AST → FableTransforms → Fable2Target → Target AST → Printer → Output
44+
```
45+
46+
1. **FSharp2Fable** (`src/Fable.Transforms/FSharp2Fable.fs`): F# AST → Fable intermediate AST
47+
2. **FableTransforms** (`src/Fable.Transforms/FableTransforms.fs`): Optimizations on Fable AST (tail-call detection, monadic trampolines, etc.)
48+
3. **Fable2Target**: Language-specific code generators, each in their own subdirectory:
49+
- `Fable2Babel.fs` → JavaScript/TypeScript (outputs Babel AST, printed by `BabelPrinter.fs`)
50+
- `Python/Fable2Python.*.fs` → Python (AST in `Python.AST.fs`, printed by `PythonPrinter.fs`)
51+
- `Rust/Fable2Rust.fs` → Rust
52+
- `Dart/Fable2Dart.fs` → Dart
53+
- `Beam/Fable2Beam.fs` → Erlang/BEAM
54+
55+
### Replacements System
56+
57+
`Replacements.fs` files map .NET BCL method calls to target language implementations. This is how `System.String.Contains()` becomes the appropriate call in each target. Each target has its own replacements file:
58+
59+
- `src/Fable.Transforms/Replacements.fs` — JavaScript/TypeScript (default)
60+
- `src/Fable.Transforms/Python/Replacements.fs`
61+
- `src/Fable.Transforms/Rust/Replacements.fs`
62+
- `src/Fable.Transforms/Dart/Replacements.fs`
63+
- `src/Fable.Transforms/Beam/Replacements.fs`
64+
65+
Shared replacement utilities are in `Replacements.Util.fs` and `Replacements.Api.fs`.
66+
67+
### Key Source Directories
68+
69+
- `src/Fable.AST/` — Core AST definitions (`Fable.fs` defines the Fable intermediate representation with types like `Expr`, `Type`, `MemberDecl`)
70+
- `src/Fable.Core/` — Attributes and interop types used in F# source code targeting Fable (e.g., `[<Emit>]`, `[<Import>]`)
71+
- `src/Fable.Transforms/` — All compilation stages, organized by target language in subdirectories
72+
- `src/Fable.Compiler/` — Compiler library (project cracking, file watching)
73+
- `src/Fable.Cli/` — CLI entry point; `Pipeline.fs` orchestrates file compilation and output
74+
- `src/fable-library-{ts,py,dart,rust,beam}/` — Runtime libraries for each target. Parts are written in F# (e.g., `src/fable-library-ts/Seq.fs`) and transpiled to the target language during build. Other targets may share F# sources from `fable-library-ts/` via linked files in their `.fsproj` (e.g., `src/fable-library-beam/Fable.Library.Beam.fsproj` links `Seq.fs` from `fable-library-ts/`). The transpiled output goes to `temp/fable-library-<target>/`
75+
- `src/quicktest*/` — Minimal projects for rapid development iteration
76+
77+
### Per-Target Structure
78+
79+
Each target language follows a consistent pattern within `src/Fable.Transforms/`:
80+
81+
- `Fable2<Target>.fs` — Main compilation from Fable AST to target AST
82+
- `<Target>.AST.fs` — Target language AST definition
83+
- `<Target>Printer.fs` — Target AST → source code string
84+
- `Replacements.fs` — .NET BCL → target language mappings
85+
86+
## Development Guidelines
87+
88+
When investigating an issue or implementing a feature for a specific target, always look at how other targets handle the same problem. Targets should stay aligned in how they solve similar features — check the equivalent `Fable2<Target>.fs` and `Replacements.fs` files for other languages before implementing.
89+
90+
The main transform files (`Fable2Babel.fs`, `Fable2Beam.fs`, `Fable2Python.Transforms.fs`, etc.) should contain only Fable AST to target AST transformations. Helper functions and utilities belong in the corresponding `.Util.fs`, `.Reflection.fs`, or similar files.
91+
92+
Be careful when modifying shared files like `FableTransforms.fs`, `Transforms.Util.fs`, `FSharp2Fable.fs`, `Replacements.Api.fs`, or `Replacements.Util.fs` — these are used by all targets, and changes can introduce regressions for targets other than the one being fixed.
93+
94+
- **`src/Fable.AST/`** — Do not modify. Changes are breaking and require a new major version of Fable.
95+
- **`src/Fable.Core/`** — Distributed on NuGet. Must not have breaking changes within a major version.
96+
97+
`src/fable-library-py/` is distributed on PyPI and must be backward-compatible within minor versions. Do not change the semantics of existing functions — instead, create a new function with a new name and update `Replacements.fs` to call it.
98+
99+
All code in `fable-library-py` must be fully type-annotated using Python 3.12+ syntax (PEP 695). Avoid `Any`, `cast()`, and `# type: ignore` — these require justification. Keep functions small and simple: extract helpers and use early returns. The Rust extension modules (`fable-library-core`) exist to provide correct .NET semantics for numerics, arrays, etc. — not for performance (the FFI crossing is expensive).
100+
101+
All transpiled Python code is type-checked with Pyright at standard settings (`./build.sh test python --type-check`). Do not introduce type-checking regressions without justification.
102+
103+
## Development Workflow
104+
105+
**Quicktest** is the fastest way to iterate (seconds vs minutes for full tests). Use it to investigate complex problems:
106+
107+
1. Edit `src/quicktest/QuickTest.fs` (or `src/quicktest-py/QuickTest.fs`, etc.)
108+
2. Ask the user to run `./build.sh quicktest <target>` — this starts a watcher that never exits, so do not run it yourself
109+
3. Output goes to `temp/tests/`
110+
111+
Quicktest is also preferred when adding debug output (e.g., `printfn` in compiler code) since running full tests with debug prints produces too much output.
112+
113+
**Test suites** are in `tests/<target>/` (e.g., `tests/Python/`, `tests/Js/Main/`). Tests are first run on .NET, then transpiled to `temp/tests/<target>/` and executed with the target's test runner. Full test runs take several minutes.
114+
115+
When adding a test, check if other targets already have a test for the same case (e.g., look in `tests/Js/Main/` before adding to `tests/Python/`) — reuse or adapt existing test patterns where possible.
116+
117+
**Never modify a test to make it pass on a target if it already passes on .NET.** If a test passes on .NET but fails on a target, the compiler or runtime library needs to be fixed — not the test.
118+
119+
## Changelogs
120+
121+
PRs must update changelogs. Always update both `src/Fable.Cli/CHANGELOG.md` and `src/Fable.Compiler/CHANGELOG.md` for changes to Fable.Transforms or fable-library. If the change touches `Fable.Core` (attributes, interop types), also update `src/Fable.Core/CHANGELOG.md`. Add entries under the `## Unreleased` section following the Keep a Changelog format with target prefix (e.g., `* [Python] Fix ...`, `* [Beam] Add ...`, `* [All] Fix ...`).
122+
123+
## Requirements
124+
125+
- .NET SDK 10+
126+
- Node.js with npm
127+
- Python 3.12+ with [uv](https://docs.astral.sh/uv/) (3.12+ required for PEP 695 type parameter syntax)
128+
- Rust toolchain (for Rust target)
129+
- Dart SDK (for Dart target)
130+
- Erlang/OTP with rebar3 (for BEAM target)

0 commit comments

Comments
 (0)