Files
foreignthon-docs/docs/contributing/core.md

3.7 KiB

Contributing to Core

foreignthon-core is the transpiler engine, CLI, and pack loader. Contributions that improve correctness, performance, or usability are welcome.


Repository

https://git.keshavanand.net/foreign-thon/foreignthon-core


Dev setup

git clone https://git.keshavanand.net/foreign-thon/foreignthon-core
cd foreignthon-core

python -m venv .venv
source .venv/bin/activate          # Windows: .venv\Scripts\activate

pip install -e ".[dev]"            # installs foreignthon + pytest + ruff

Verify the install:

fpy --version
pytest

Running tests

pytest                  # all tests
pytest -v               # verbose
pytest -k postfix       # filter by name

Tests live in tests/test_engine.py. They use a local test_pack.json fixture (a copy of the Spanish pack) so no installed language pack is needed.


Code style

ForeignThon uses Ruff for linting and formatting:

ruff check src/         # lint
ruff format src/        # format

The CI gate runs both. A PR that fails either will not be merged.

Line length is 88. Import order follows the I rule set (isort-compatible).


Project layout

foreignthon-core/
├── src/
│   └── foreignthon/
│       ├── __init__.py      # version
│       ├── cli.py           # click commands (fpy)
│       ├── errors.py        # bilingual error hook
│       ├── pack.py          # pack discovery and validation
│       ├── template.json    # canonical list of all pack keys
│       └── transpiler.py    # tokenizer-based engine
└── tests/
    ├── test_engine.py
    └── test_pack.json       # Spanish fixture (no install needed)

Adding new keywords or builtins

template.json is the single source of truth for the full set of keywords, builtins, exceptions, and stdlib names that all language packs must cover.

To add a new entry (e.g. a new builtin):

  1. Add it to template.json with the English value as the default.
  2. Add a matching entry to test_pack.json (Spanish values).
  3. Update _build_mapping() in transpiler.py if a new section is needed.
  4. Bump foreignthon-core version.
  5. Announce to language pack maintainers so they can update their packs.

Do not add entries to template.json that are specific to one language pack.


Adding a new CLI command

All commands are defined in cli.py using Click.

  • Add your command as a function decorated with @main.command().
  • Include a docstring — Click uses it as the --help text.
  • Add CONTEXT_SETTINGS to every command for consistent -h support.
  • Write tests in tests/test_engine.py or a new test file.

Submitting a PR

  1. Fork the repository on Gitea.
  2. Create a branch: git checkout -b feature/my-change.
  3. Make your change, add or update tests, run pytest and ruff check.
  4. Open a PR with a clear description of the problem and the fix.

For large changes (new features, engine behaviour changes), open an issue first to discuss before writing code.


What not to change

  • template.json keys should only grow, never shrink — removing a key is a breaking change for all existing language packs.
  • The tokenizer-based approach in transpiler.py is intentional. Do not replace it with a regex or AST-based approach without a very strong reason — the tokenizer correctly handles strings, comments, and f-strings without any special casing.
  • The bilingual error format ([XX] ForeignName: msg / [EN] EnglishName: msg) is part of the public interface. Do not change the format without a major version bump.