A CLAUDE.md is just a markdown file at the root of your repo. Copy the content below into your own project's CLAUDE.md to give your agent the same context.
npx versuz@latest install acacode-swagger-typescript-api --kind=claude-mdcurl -o CLAUDE.md https://raw.githubusercontent.com/acacode/swagger-typescript-api/HEAD/CLAUDE.md# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Project Overview
swagger-typescript-api generates TypeScript API clients (Fetch or Axios) from OpenAPI 2.0/3.0 specifications. It works as both a CLI tool (`sta generate` / `swagger-typescript-api generate`) and a library (`generateApi()`). The package outputs dual ESM/CJS formats.
## Common Commands
```bash
bun install --frozen-lockfile # Install dependencies
bun run build # Build with tsdown (dist/index.mjs, dist/index.cjs, dist/cli.mjs, dist/cli.cjs)
bun run test # Run all tests (vitest, 30s timeout)
bun run test -- tests/simple.test.ts # Run a specific test file
bun run test -- tests/spec/axios/basic.test.ts # Run a single spec test
bun run test -- -t "axios" # Run tests matching a name pattern
bun run test -- --update # Update snapshots
bun run lint # Lint with biome check
bun run format # Format with biome format --write
bun run format:check # Check formatting
```
## Architecture
### Code Generation Pipeline (CodeGenProcess.start)
1. **Template resolution** — `TemplatesWorker` loads templates from `templates/base/`, `templates/default/` (or `templates/modular/`), and optional custom templates. Priority: custom > base > original.
2. **Schema fetching** — `SwaggerSchemaResolver` loads specs from file/URL/inline, supports JSON and YAML.
3. **Swagger 2→3 conversion** — Swagger 2.0 specs are converted to OpenAPI 3.0 via `swagger2openapi`.
4. **Component registration** — `SchemaComponentsMap` registers all `#/components/schemas/*` entries with discriminators and enums sorted first.
5. **Schema parsing** — `SchemaParserFabric` creates type-specific parsers (`MonoSchemaParser` subclasses in `src/schema-parser/base-schema-parsers/` and `complex-schema-parsers/`). Each parser handles one type: enum, object, array, primitive, discriminator, oneOf, anyOf, allOf, not.
6. **Route parsing** — `SchemaRoutes` (`src/schema-routes/schema-routes.ts`) walks all paths/methods to create `ParsedRoute` objects with request/response types, parameters, and module grouping.
7. **Template rendering** — Eta engine renders `.ejs` templates. Templates use `includeFile()` with path prefixes (`@base/`, `@default/`, `@modular/`, `@custom/`).
8. **Formatting** — `CodeFormatter` removes unused imports via TypeScript LanguageService, then formats with Biome.
9. **Optional JS translation** — `JavascriptTranslator` compiles TS output to JS + `.d.ts` using the TypeScript compiler API.
### Key Entry Points
- `index.ts` (root) — CLI entry point using citty
- `src/index.ts` — Library entry, exports `generateApi()`, `generateTemplates()`, constants
- `src/code-gen-process.ts` — Main orchestrator class
- `src/configuration.ts` — `CodeGenConfig` with all options and `Ts` code generation constructs
- `types/index.ts` — All public TypeScript type definitions
### Extension Points
- **13 lifecycle hooks** — `onInit`, `onCreateComponent`, `onPreParseSchema`, `onParseSchema`, `onCreateRoute`, `onPrepareConfig`, `onFormatTypeName`, `onFormatRouteName`, `onCreateRouteName`, `onCreateRequestParams`, `onPreBuildRoutePath`, `onBuildRoutePath`, `onInsertPathParam`
- **Custom schema parsers** — Override via `config.schemaParsers` with `MonoSchemaParser` subclasses
- **Custom templates** — User-provided templates override by matching filename
- **Code generation constructs** — `codeGenConstructs` option overrides TS primitives (`ArrayType`, `UnionType`, `IntersectionType`, `RecordType`, etc.)
- **Patchable instances** — `PATCHABLE_INSTANCES` in `CodeGenProcess` allows cross-instance injection
### Template System
Templates live in `templates/` with three tiers:
- `base/` — Shared templates (data-contracts, http-client, route-docs, jsdoc)
- `default/` — Single-file output mode (api.ejs, procedure-call.ejs, route-types.ejs)
- `modular/` — Multi-file output mode (`--modular` flag, generates separate files per route module)
Templates receive `it.config`, `it.modelTypes`, `it.routes`, `it.utils` as context variables.
### Test Structure
- `tests/simple.test.ts` — Snapshot tests running all fixture schemas (v2.0 + v3.0) with basic options
- `tests/extended.test.ts` — Same schemas with all extraction options enabled
- `tests/spec/{feature}/basic.test.ts` — 44 feature-specific tests, each with its own schema.json and snapshot
- Tests call `generateApi()`, read output files, and compare against vitest snapshots
## Technical Details
- **Package manager:** Bun
- **Module system:** ESM (`"type": "module"`)
- **Build:** tsdown (esbuild-based, outputs ESM + CJS with `.d.ts`)
- **Node requirement:** >=20
- **Linting/Formatting:** Biome (not ESLint/Prettier)
- **Config file support:** `swagger-typescript-api.config.{ts,js,json}` via c12
- **CI:** Tests across Node 20, 22, 24, 25; format check → build → test
## Style Guide
### Formatting
Biome handles all formatting. Do not manually adjust formatting — run `bun run format` and accept the result. Key settings (via `.editorconfig`): 2-space indentation, LF line endings, UTF-8 encoding.
### Imports
- Use `import type` for type-only imports. Keep type imports separate from value imports.
- Use namespace imports (`import * as`) for Node.js built-in modules.
- Use named imports for specific utilities from libraries.
- All relative imports must include the `.js` extension (ESM requirement, even for `.ts` source files).
- Order: Node builtins first, then external packages, then internal modules. Biome enforces this.
```typescript
import * as fs from "node:fs/promises";
import * as path from "node:path";
import { compact, merge } from "es-toolkit";
import type { GenerateApiConfiguration } from "../types/index.js";
import { CodeFormatter } from "./code-formatter.js";
```
### Utilities
- Use `es-toolkit` (and `es-toolkit/compat`) instead of lodash. The `createLodashCompat()` function exists only for backwards compatibility in templates — do not use it in source code.
- Use `consola` for all logging (`consola.info`, `consola.debug`, `consola.warn`, `consola.success`). Do not use `console.log`.
### Comments
- Avoid comments that restate the type signature or function name. A comment like `/** Returns the schema */` on `getSchema()` adds no value.
- Use comments to explain _why_, not _what_. If the code is doing something non-obvious or working around a known issue, explain the reasoning.
- When documentation seems redundant with the type signature, it is still acceptable in broadly-used public API surfaces.
### Defensive Practices
- Prefer `unknown` over `any`. Use `any` only when interfacing with untyped external APIs where `unknown` would require excessive casting.
- Avoid `@ts-ignore` — use `@ts-expect-error` with the specific error code instead, so the suppression breaks when the underlying issue is fixed.
- Avoid catch-all pattern matches. Prefer exhaustive handling to enable compiler warnings when new variants are added.
- Use labeled arguments (object parameters) for functions with multiple parameters of the same type to prevent argument transposition.
- Annotate the types of ignored return values to catch signature changes at compile time.
## Commit Messages
Do **not** use Conventional Commits format (e.g., `feat:`, `fix:`, `chore:`).
- Use imperative mood: "Add feature" not "Added feature" or "Adds feature"
- Focus on **what** changed, not implementation details
- Keep the subject line under 72 characters
- Do not start with "This commit..." or "I changed..."
Good: `Add retry logic for failed API calls`
Bad: `feat: add retry logic`
## Pull Requests
PR titles follow the same rules as commit messages (no Conventional Commits, imperative mood).
PR descriptions should be detailed enough that a reader can understand the change without external context. Include:
- **Problem**: Define the issue clearly. Describe symptoms (errors, crashes, performance degradation) that justify the change.
- **Solution**: Explain the approach taken and why it was chosen over alternatives.
- **Verification**: How to test the change. Include specific steps or evidence (screenshots, metrics).
- **Performance claims**: Back up with concrete numbers (before/after benchmarks).
Keep descriptions self-contained. When linking to issues or discussions, summarize the relevant points rather than relying on the reader to follow links.
### Reduce reviewer cognitive load
- Break large changes into smaller, focused PRs that each address a single concern.
- Structure commits to tell a story: each commit should be a logical, reviewable unit.
- If a PR requires significant context, add inline comments on your own diff to guide the reviewer through complex sections.