|
| 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 | +Squint is a ClojureScript dialect that compiles to JavaScript with minimal bundle size. It uses native JS data structures (objects, arrays, Maps, Sets) instead of ClojureScript's persistent data structures, producing readable ES module output. |
| 8 | + |
| 9 | +The compiler itself is written in Clojure/ClojureScript (`.cljc` files), compiled to JS via shadow-cljs, then runs on Node.js. |
| 10 | + |
| 11 | +## Build & Development Commands |
| 12 | + |
| 13 | +Requires: Node.js, Java (for shadow-cljs), [Babashka](https://babashka.org/) (`bb`) |
| 14 | + |
| 15 | +```bash |
| 16 | +bb build # Full release build (deletes lib/, rebuilds via shadow-cljs) |
| 17 | +bb watch # Dev mode: shadow-cljs watch with test config |
| 18 | +bb dev # Watch + playground server (parallel) |
| 19 | +``` |
| 20 | + |
| 21 | +### Testing |
| 22 | + |
| 23 | +```bash |
| 24 | +bb test:node # Primary: compile tests via shadow-cljs, run with node lib/squint_tests.js, plus REPL and project tests |
| 25 | +bb test:bb # Run compiler tests in Babashka |
| 26 | +bb test:clj # Run compiler tests in Clojure JVM (clojure -X:test) |
| 27 | +bb test:libs # Run against external projects (clojure-mode) |
| 28 | +``` |
| 29 | + |
| 30 | +The `bb test:node` pipeline: shadow-cljs compile → `node lib/squint_tests.js` → node REPL tests → test-project integration test. |
| 31 | + |
| 32 | +There is no built-in way to run a single test. Tests use `clojure.test` and live in `test/squint/`. The main test file is `test/squint/compiler_test.cljs`. |
| 33 | + |
| 34 | +## Architecture |
| 35 | + |
| 36 | +### Compilation Pipeline |
| 37 | + |
| 38 | +``` |
| 39 | +ClojureScript source → edamame (parser) → compiler (emit) → JavaScript string |
| 40 | +``` |
| 41 | + |
| 42 | +The compiler is a direct string-emitting compiler, not an AST-based one. The main entry point is `emit` in `compiler_common.cljc`, which dispatches on expression type. Special forms are handled by `emit-special` (a multimethod in `compiler.cljc`). |
| 43 | + |
| 44 | +### Key Source Files |
| 45 | + |
| 46 | +- **`src/squint/compiler.cljc`** — Main compiler: special form dispatch (`emit-special`), built-in macro table, `compile-string` |
| 47 | +- **`src/squint/compiler_common.cljc`** — Shared compiler state (dynamic vars like `*aliases*`, `*cljs-ns*`, `*async*`), `emit` function, infix operators, return handling |
| 48 | +- **`src/squint/core.js`** — JavaScript runtime library (core functions like `assoc`, `get`, `map`, `filter`, etc.) |
| 49 | +- **`src/squint/internal/macros.cljc`** — Built-in macro implementations (`->`, `cond`, `doseq`, `for`, `when`, etc.) |
| 50 | +- **`src/squint/internal/fn.cljc`** — Function compilation (`fn`, `defn`, multi-arity, variadic args) |
| 51 | +- **`src/squint/internal/destructure.cljc`** — Destructuring (`let`, binding forms) |
| 52 | +- **`src/squint/internal/loop.cljc`** — `loop`/`recur` compilation |
| 53 | +- **`src/squint/defclass.cljc`** — `defclass` special form (JS class emission) |
| 54 | +- **`src/squint/internal/deftype.cljc`** — `deftype`/`defprotocol` support |
| 55 | +- **`src/squint/internal/cli.cljs`** — CLI entry point (`npx squint`) |
| 56 | +- **`src/squint/repl/nrepl_server.cljs`** — nREPL server (experimental) |
| 57 | + |
| 58 | +### Compiler Environment |
| 59 | + |
| 60 | +The `env` map passed through compilation controls emission behavior: |
| 61 | +- `:context` — `:expr`, `:return`, or `:statement` (controls whether `return` is emitted) |
| 62 | +- `:top-level` — whether at module top level |
| 63 | +- `:async` / `:gen` — inside async/generator function |
| 64 | + |
| 65 | +### Data Structure Mapping |
| 66 | + |
| 67 | +| Squint | JavaScript | |
| 68 | +|---------------------|-------------------------| |
| 69 | +| `{:a 1}` | `{a: 1}` | |
| 70 | +| `[1 2 3]` | `[1, 2, 3]` | |
| 71 | +| `:foo` | `"foo"` | |
| 72 | +| `#{1 2}` | `new Set([1, 2])` | |
| 73 | +| `assoc`, `conj` | shallow copy (spread) | |
| 74 | +| `assoc!`, `conj!` | mutate in place | |
| 75 | + |
| 76 | +### Test Utilities (`test/squint/test_utils.cljs`) |
| 77 | + |
| 78 | +- `jss!` — compile a form to a JS string |
| 79 | +- `js!` — compile and eval, returns `[value js-string]` |
| 80 | +- `jsv!` — compile and eval, returns just the value |
| 81 | +- `eq` — deep equality via lodash (handles arrays, objects, Maps, Sets) |
| 82 | + |
| 83 | +### shadow-cljs Build |
| 84 | + |
| 85 | +The squint compiler itself is compiled from ClojureScript to JS via shadow-cljs. The build config (`shadow-cljs.edn`) produces ES modules under `lib/` with multiple module splits (compiler, CLI, nREPL, etc.). |
0 commit comments