Contributing to expr-eval¶
Thank you for your interest in contributing to expr-eval! This guide will help you get started with development.
Audience: Project contributors
Development Setup¶
Prerequisites¶
- Node.js 18 or higher
- npm 9 or higher
Getting Started¶
-
Clone the repository
-
Install dependencies
-
Run tests to verify setup
Project Structure¶
expr-eval/
├── src/ # Source code
│ ├── index.ts # Main entry point
│ ├── config/ # Parser configuration
│ ├── core/ # Core evaluation logic
│ ├── errors/ # Error types and handling
│ ├── functions/ # Built-in functions
│ │ ├── array/ # Array functions
│ │ ├── math/ # Math functions
│ │ ├── object/ # Object functions
│ │ ├── string/ # String functions
│ │ └── utility/ # Utility functions
│ ├── language-service/ # IDE integration
│ ├── operators/ # Operator implementations
│ │ ├── binary/ # Binary operators
│ │ └── unary/ # Unary operators
│ ├── parsing/ # Tokenizer and parser
│ ├── types/ # TypeScript type definitions
│ └── validation/ # Expression validation
├── test/ # Test files (mirrors src/ structure)
├── docs/ # Documentation
├── benchmarks/ # Performance benchmarks
└── samples/ # Example applications
Development Workflow¶
Running Tests¶
# Run all tests
npm test
# Run tests in watch mode
npm run test:watch
# Run tests with coverage
npm run test:coverage
Linting¶
Building¶
Benchmarks¶
# Run all benchmarks
npm run bench
# Run specific benchmark categories
npm run bench:parsing
npm run bench:evaluation
npm run bench:memory
Code Style¶
TypeScript Guidelines¶
- Use explicit types for function parameters and return values
- Prefer
interfaceovertypefor object shapes - Use
readonlyfor properties that shouldn't be modified - Document public APIs with TSDoc comments
Naming Conventions¶
- Files:
kebab-case.ts - Classes:
PascalCase - Functions/Methods:
camelCase - Constants:
UPPER_SNAKE_CASE - Interfaces:
PascalCase(noIprefix)
Example¶
/**
* Evaluates a mathematical expression.
* @param expression - The expression string to evaluate
* @param variables - Variable values for the expression
* @returns The evaluation result
*/
export function evaluate(
expression: string,
variables: Record<string, Value>
): Value {
// Implementation
}
Testing Guidelines¶
Test File Organization¶
- Test files should mirror the source structure
- Use descriptive test names that explain the expected behavior
- Group related tests with
describeblocks
Example Test¶
import { describe, it, expect } from 'vitest';
import { Parser } from '../src';
describe('Parser', () => {
describe('evaluate', () => {
it('should evaluate simple arithmetic', () => {
const parser = new Parser();
expect(parser.evaluate('2 + 3')).toBe(5);
});
it('should substitute variables', () => {
const parser = new Parser();
expect(parser.evaluate('x * 2', { x: 5 })).toBe(10);
});
});
});
Pull Request Process¶
-
Create a feature branch
-
Make your changes
- Write tests for new functionality
- Update documentation as needed
-
Follow the code style guidelines
-
Run checks locally
-
Commit with a descriptive message
Follow Conventional Commits format:
- feat: - New features
- fix: - Bug fixes
- docs: - Documentation changes
- test: - Test additions or modifications
- refactor: - Code refactoring
- perf: - Performance improvements
- Push and create a PR
Adding New Functions¶
- Create the function in the appropriate
src/functions/subdirectory - Export it from the subdirectory's
index.ts - Register it in the parser's default functions
- Add tests in the corresponding
test/functions/file - Document the function in
docs/syntax.md
Adding New Operators¶
- Create the operator in
src/operators/binary/orsrc/operators/unary/ - Add the operator token to the tokenizer
- Add parser support for the operator precedence
- Register it in the parser configuration
- Add tests and documentation
Questions?¶
If you have questions about contributing, feel free to: - Open an issue on GitHub - Check existing issues and discussions
Thank you for contributing!