Thank you for your interest in contributing to DeepL CLI. This guide covers everything you need to get started.
This project has a Code of Conduct to which all contributors must adhere when participating in the project. Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting open-source@deepl.com and/or a project maintainer.
- Node.js >= 20.0.0
- npm >= 9.0.0
- A DeepL API key (free tier works for development)
# Clone the repository
git clone https://github.com/DeepLcom/deepl-cli.git
cd deepl-cli
# Install dependencies
npm install
# Build the project
npm run build
# Link for local testing
npm link
# Verify it works
deepl --versionThis project follows Test-Driven Development (TDD). Every change goes through the Red-Green-Refactor cycle:
- Red -- Write a failing test that defines the expected behavior.
- Green -- Write the minimum code to make the test pass.
- Refactor -- Improve the code while keeping tests green.
- Commit -- Save your progress with a descriptive message.
# Run without building
npm run dev -- translate "Hello" --to es
# Or use the linked global command
deepl translate "Hello" --to es# Run all tests
npm test
# Run by category
npm run test:unit
npm run test:integration
npm run test:e2e
# Run a specific file
npm test -- translation.test.ts
# Watch mode (useful during TDD)
npm test -- --watch
# Coverage report
npm run test:coverageNew features must include all three test types:
| Type | Location | Purpose |
|---|---|---|
| Unit | tests/unit/ |
Test functions/classes in isolation with mocked dependencies |
| Integration | tests/integration/ |
Test component interactions; use nock for HTTP mocking |
| E2E | tests/e2e/ |
Test complete CLI workflows from input to output |
Use DEEPL_CONFIG_DIR (set to a temp directory) to isolate test configuration from your real settings.
- Files:
kebab-case.ts - Classes/Types/Interfaces:
PascalCase - Functions/Variables:
camelCase - Constants:
UPPER_SNAKE_CASE
- Strict mode is enabled. Avoid
any. - Prefer
async/awaitover raw promises. - Use Zod for runtime validation where appropriate.
src/
cli/ # CLI commands and argument parsing
services/ # Business logic
api/ # DeepL API client
storage/ # SQLite cache and config management
utils/ # Shared utility functions
types/ # Type definitions
tests/
unit/ # Unit tests
integration/ # Integration tests
e2e/ # End-to-end tests
npm run lint # Check for issues
npm run lint:fix # Fix lint issues automatically
npm run type-check # TypeScript compilation check
npm run format # Format code with Prettier
npm run format:check # Check code formatting
npm run examples # Run all example scripts
npm run examples:fast # Run examples (skip slow ones)Use Conventional Commits:
<type>(<scope>): <description>
| Type | When to use |
|---|---|
feat |
New feature |
fix |
Bug fix |
refactor |
Code change that neither fixes a bug nor adds a feature |
test |
Adding or updating tests |
docs |
Documentation only |
chore |
Maintenance (deps, config, CI) |
perf |
Performance improvement |
feat(translate): add XML tag handling options
fix(cache): prevent stale entries after TTL expiry
test(glossary): add integration tests for multilingual glossaries
docs(api): document --style-id flag usage
Group tests in the same commit as the code they validate.
Before beginning work, please create an issue describing the changes you plan to contribute, to avoid wasting or duplicating effort. We will then let you know whether we would accept the changes.
Contributions must be licensed under the same license as the project: MIT License.
- Create a branch from
mainfor your change. - Write tests first, then implement the feature (TDD).
- Run the full check suite before pushing:
npm test && npm run lint && npm run type-check && npm run build
- Open a PR with a clear description covering:
- Summary of the change and motivation
- List of specific changes
- Backward compatibility notes
- Test coverage summary
- Address review feedback with additional commits (do not force-push).
- All tests pass (
npm test) - Linter passes (
npm run lint) - TypeScript compiles (
npm run type-check) - New code includes unit, integration, and e2e tests
- Commit messages follow conventional commits format
-
CHANGELOG.mdupdated under Unreleased section -
README.mdupdated if user-facing feature changed -
docs/API.mdupdated if command/flag added or changed - Example script added/updated in
examples/for new features
Here is a condensed walkthrough for adding a command called mycommand:
- Write tests in
tests/unit/,tests/integration/, andtests/e2e/. - Create the command handler at
src/cli/commands/mycommand.ts. - Create the registration file at
src/cli/commands/register-mycommand.tsto wire the command into Commander.js. - Add a service (if needed) at
src/services/mycommand-service.tsfor business logic. - Register the command in
src/cli/index.ts. - Add an example script at
examples/NN-mycommand.shand register it inexamples/run-all.sh. - Update documentation:
docs/API.md(command reference) andREADME.md(usage section).
Follow the existing commands (e.g., translate, write, glossary) as templates.
When filing a bug report, include:
- DeepL CLI version (
deepl --version) - Node.js version (
node --version) - Operating system and version
- Steps to reproduce the issue
- Expected vs. actual behavior
- Relevant error output
- CLAUDE.md -- Detailed development guidelines, TDD workflow, and testing strategy
- docs/API.md -- Complete CLI command reference
- DeepL API Docs -- Official API documentation