Thank you for your interest in contributing to tapi! This guide will help you get started with development and contributing to the project.
- Node.js (v18 or higher)
- npm (v8 or higher)
- Git
- TypeScript knowledge
- Basic understanding of PAWN and SA-MP/open.mp
-
Fork and clone the repository:
git clone https://github.com/yourusername/tapi.git cd tapi -
Install dependencies:
npm install
-
Build the project:
npm run build
-
Link for local development:
npm run dev
This builds and creates a global symlink so you can test
tapicommands locally. -
Run tests:
npm test
tapi/
├── src/ # TypeScript source code
│ ├── commands/ # CLI command implementations
│ │ ├── init/ # Project initialization
│ │ ├── build/ # Code compilation
│ │ ├── start/ # Server management
│ │ ├── config/ # Configuration management
│ │ ├── install/ # Package installation
│ │ └── kill/ # Process termination
│ ├── core/ # Core functionality
│ │ └── manifest.ts # pawn.json handling
│ ├── utils/ # Utility functions
│ │ ├── logger.ts # Logging system
│ │ ├── config.ts # User configuration
│ │ ├── banner.ts # CLI branding
│ │ └── serverState.ts # Server process management
│ └── templates/ # Project templates
│ ├── projects/ # Code templates
│ ├── vscode/ # VS Code integration
│ └── common/ # Shared templates
├── tests/ # Test suite
│ ├── unit/ # Unit tests
│ ├── integration/ # Integration tests
│ └── fixtures/ # Test data
├── dist/ # Compiled JavaScript (generated)
└── bin/ # CLI entry point
-
Create command directory:
mkdir src/commands/yourcommand
-
Create main implementation:
// src/commands/yourcommand/yourcommand.ts import { Command } from 'commander'; import { showBanner } from '../../utils/banner'; import { logger } from '../../utils/logger'; export default function (program: Command): void { program .command('yourcommand') .description('Description of your command') .option('-o, --option <value>', 'command option') .action(async (options) => { showBanner(false); try { // Your command logic here logger.success('✅ Command completed successfully'); } catch (error) { logger.error(`❌ Command failed: ${error instanceof Error ? error.message : 'unknown error'}`); process.exit(1); } }); }
-
Create documentation:
<!-- src/commands/yourcommand/README.md --> # `yourcommand` Command Brief description of what the command does. ## Usage ```bash tapi yourcommand [options]
Option Description Default -o, --option <value>Option description - -
Add tests:
// tests/unit/yourcommand.test.ts import yourcommand from '../../src/commands/yourcommand/yourcommand'; describe('yourcommand', () => { test('should work correctly', () => { // Your tests here }); });
- Run all tests:
npm test - Run tests with coverage:
npm run test:coverage - Run tests in watch mode:
npm run test:watch - Run specific test:
npm test -- yourtest.test.ts
We use ESLint and TypeScript for code quality:
- Lint code:
npm run lint - Fix linting issues:
npm run lint:fix - Type checking:
npm run type-check
- Development build:
npm run build - Production build:
npm run build && npm run dev
- User Experience First: Always consider the developer using tapi
- Cross-Platform: Support Windows, macOS, and Linux
- Clear Error Messages: Provide helpful, actionable error messages
- Consistent API: Follow established patterns in the codebase
- Documentation: Document all public APIs and commands
// ✅ Good: Use interfaces for type safety
interface BuildOptions {
verbose?: boolean;
output?: string;
}
// ✅ Good: Use proper error handling
try {
await buildProject(options);
logger.success('✅ Build completed');
} catch (error) {
logger.error(`❌ Build failed: ${error instanceof Error ? error.message : 'unknown error'}`);
process.exit(1);
}
// ✅ Good: Use descriptive function names
async function validateServerConfiguration(configPath: string): Promise<void>
// ❌ Avoid: Using 'any' type
function processData(data: any): any // Use proper types instead// ✅ Use consistent emoji patterns
logger.success('✅ Operation completed');
logger.error('❌ Operation failed');
logger.warn('⚠️ Warning message');
logger.info('ℹ️ Information');
logger.working('Working on task...');
// ✅ Structure output with headings
logger.heading('=== Building Project ===');
logger.subheading('Compilation Results:');
logger.list(['✅ File 1 compiled', '❌ File 2 failed']);describe('CommandName', () => {
beforeEach(() => {
// Setup for each test
});
afterEach(() => {
// Cleanup after each test
});
describe('when condition X', () => {
test('should behave correctly', async () => {
// Arrange
const input = 'test input';
// Act
const result = await functionUnderTest(input);
// Assert
expect(result).toBe('expected output');
});
});
});- Happy path scenarios
- Error conditions
- Edge cases
- Cross-platform behavior
- File system operations
- External process interactions
-
Create a feature branch:
git checkout -b feature/your-feature-name
-
Make your changes following the coding guidelines
-
Add tests for new functionality
-
Update documentation if needed
-
Ensure all checks pass:
npm run build npm test npm run lint -
Test manually with
npm run dev
-
Clear title: Use descriptive PR titles
- ✅ "Add watch mode to start command"
- ❌ "Fix stuff"
-
Detailed description:
- What does this PR do?
- Why is this change needed?
- How has it been tested?
- Any breaking changes?
-
Link related issues using keywords:
Fixes #123 Closes #456 Related to #789 -
Keep PRs focused: One feature/fix per PR
-
Update documentation for user-facing changes
Include:
- tapi version:
tapi --version - Operating system: Windows 10, macOS 12, Ubuntu 20.04, etc.
- Node.js version:
node --version - Steps to reproduce
- Expected behavior
- Actual behavior
- Error messages (with full stack traces)
- Project structure if relevant
Include:
- Use case: Why is this feature needed?
- Proposed solution: How should it work?
- Alternatives considered: Other ways to solve the problem
- Examples: Show how the feature would be used
// Use logger for debugging
logger.detail('Debug info in verbose mode');
// Use environment variables for debug builds
if (process.env.TAPI_DEBUG) {
console.log('Debug information');
}# Build and link for testing
npm run dev
# Test in a sample project directory
cd /path/to/test/project
tapi init
tapi build
tapi start --watchTemplates are in src/templates/ and get copied to dist/templates/ during build. After modifying templates:
npm run copy-templates- Commander.js - CLI framework
- Inquirer.js - Interactive prompts
- Chokidar - File watching
- Jest - Testing framework
- Questions? Open a GitHub Discussion
- Found a bug? Open a GitHub Issue
- Want to contribute? Open a Pull Request
- Need help? Check existing issues and discussions
By contributing to tapi, you agree that your contributions will be licensed under the same license as the project.
Thank you for contributing to tapi! 🎉