Contributing
We welcome contributions to binja! This guide will help you get started.
Getting Started
Fork and Clone
# Fork the repo on GitHub, then:git clone https://github.com/YOUR_USERNAME/binja.gitcd binjaInstall Dependencies
bun installRun Tests
bun testRun Specific Tests
bun test test/filters.test.tsbun test test/runtime.test.tsProject Structure
binja/├── src/│ ├── index.ts # Main entry, Environment class│ ├── cli.ts # CLI tool│ ├── lexer/ # Tokenizer│ ├── parser/ # AST generator│ ├── runtime/ # Template execution│ ├── compiler/ # AOT compilation│ ├── filters/ # Built-in filters│ ├── tests/ # Built-in tests (is operator)│ ├── engines/ # Multi-engine support│ ├── ai/ # AI linting│ └── debug/ # Debug panel├── test/ # Test files└── examples/ # Usage examplesDevelopment Workflow
Adding a New Filter
- Add filter in
src/filters/index.ts:
export const builtinFilters: Record<string, FilterFunction> = { // ...existing filters
myfilter: (value: any, arg?: any): any => { // Filter logic return result },}-
Add inline version in
src/runtime/index.tsfor performance (optional but recommended). -
Add tests in
test/filters.test.ts:
test('myfilter', async () => { const result = await render('{{ value|myfilter }}', { value: 'test' }) expect(result).toBe('expected')})Adding a New Tag
- Add token type in
src/lexer/tokens.ts(if needed) - Add AST node type in
src/parser/nodes.ts - Add parsing logic in
src/parser/index.ts - Add execution logic in
src/runtime/index.ts - Add tests
Adding a New Engine
- Create directory
src/engines/{engine}/ - Create
lexer.ts- tokenizes the engine’s syntax - Create
parser.ts- converts tokens to binja’s common AST - Create
index.tswithparse(),compile(),render()functions - Register in
src/engines/index.ts - Add tests in
test/engines.test.ts
Code Style
- Use TypeScript
- Use
async/awaitover Promises - Use
constoverletwhere possible - Add JSDoc comments for public APIs
- Follow existing code patterns
Commit Messages
Use conventional commits:
feat: add new filterfix: correct date formattingdocs: update READMEtest: add filter testsrefactor: simplify parserPull Request Process
-
Create a feature branch:
Terminal window git checkout -b feat/my-feature -
Make your changes and commit
-
Run tests and type check:
Terminal window bun testbun run typecheck -
Push and create PR:
Terminal window git push origin feat/my-feature -
Fill out the PR template
Testing Guidelines
- All tests use Bun’s test runner
- Tests should be async (render returns Promise)
- Test file naming:
{feature}.test.ts - Replicate Jinja2’s behavior where applicable
import { describe, test, expect } from 'bun:test'import { render, Environment } from '../src'
describe('Feature Name', () => { test('description', async () => { const result = await render('{{ value|filter }}', { value: 'test' }) expect(result).toBe('expected') })})Questions?
- Open an issue for bugs or feature requests
- Use discussions for questions
Thank you for contributing!