Skip to content

Latest commit

Β 

History

History
443 lines (310 loc) Β· 11.8 KB

File metadata and controls

443 lines (310 loc) Β· 11.8 KB

🀝 Contributing to TinyFrameJS

Thank you for your interest in contributing to TinyFrameJS, the high-performance JavaScript engine for tabular data processing with a modular, functional architecture. We welcome contributions of all kinds β€” code, docs, benchmarks, ideas.


πŸ›  Repository Overview

This repository is a monorepo part of the AlphaQuantJS ecosystem and contains:

  • βœ… packages/core: The core tabular engine with DataFrame, Series, and ColumnVector implementations
  • βœ… packages/io: Input/output functionality for CSV, JSON, Excel
  • βœ… packages/viz: Visualization methods for charts and plots
  • βœ… packages/quant: Technical analysis and quantitative methods
  • βœ… packages/utils: Shared utilities and helper functions
  • βœ… Vitest-based unit tests
  • βœ… Benchmarks vs competitors in /benchmarks

Project structure is in README.md


πŸ‘Œ Modular Structure and Method Registration

Allows adding new methods in a "plug-and-play" style β€” just create a file with your method and export it in a barrel file.

Step-by-Step Guide to Adding a New Method

  1. Create a file with your method
    In the packages/core/src/methods/dataframe/aggregation/ directory, create a file yourNew.js:

    /**
     * yourNew - example of a new aggregation method
     *
     * @param {{ validateColumn(frame, column): void }} deps - Dependencies
     * @returns {(frame: DataFrame, column: string) => any} - Function for working with DataFrame
     */
    export const yourNew =
      ({ validateColumn }) =>
      (frame, column) => {
        validateColumn(frame, column);
        // Your logic here
        return; /* result */
      };
  2. Add the method to the barrel file
    Open packages/core/src/methods/dataframe/aggregation/pool.js and add:

    // Add along with other exports
    export { yourNew } from './yourNew.js';
  3. Method Registration
    All methods are automatically registered via extendDataFrame in the file packages/core/src/methods/dataframe/aggregation/index.js:

    import { DataFrame } from '../../../core/DataFrame.js';
    import { extendDataFrame } from '../../../core/extendDataFrame.js';
    import * as pool from './pool.js';
    
    // Dependencies
    import { validateColumn } from '../../../utils/validators.js';
    
    const deps = { validateColumn };
    
    // Register methods
    extendDataFrame(DataFrame.prototype, pool);
    
    // Export methods for direct use
    export * from './pool.js';
  4. Using the new method

    import { DataFrame } from '@tinyframejs/core';
    
    const df = new DataFrame({ x: [1, 2, 3], y: [4, 5, 6] });
    
    // The method is automatically available in DataFrame
    const result = df.yourNew('x');

    Done! Your method works without needing to modify other files or the library core.

Adding Methods to Namespaces

For specialized methods that belong to a specific domain (like technical analysis, visualization, etc.), use namespaces:

  1. Create a method in the appropriate package

    // packages/quant/src/methods/ta/sma.js
    export const sma = 
      ({ validateColumn }) =>
      (frame, column, period = 14) => {
        validateColumn(frame, column);
        // Implementation
        return result;
      };
  2. Register with namespace

    // packages/quant/src/methods/ta/index.js
    import { DataFrame } from '@tinyframejs/core';
    import { extendDataFrame } from '@tinyframejs/core';
    import * as taMethods from './pool.js';
    
    // Register methods in the 'ta' namespace
    extendDataFrame(DataFrame.prototype, taMethods, { namespace: 'ta' });
  3. Usage

    import { DataFrame } from '@tinyframejs/core';
    import '@tinyframejs/quant'; // Registers methods
    
    const df = new DataFrame({ close: [100, 101, 102, 101, 99] });
    
    // Access through namespace
    const smaValues = df.ta.sma('close', 3);

πŸ•Š Git Workflow and Branch Structure

For project organization, we use the following branch structure:

πŸ“Œ Main Branches:

  • main

    • Production version.
    • Ready for release.
    • Each commit is stable and tested code.
  • dev

    • Main development branch.
    • All completed feature branches are merged here.
    • May contain minor bugs and improvements in progress.
    • Regularly undergoes integration testing.

πŸ“Œ Feature Branches:

For each task, issue, or feature, create a separate branch from dev:

  • Naming format:

    feature/<feature-name>
    fix/<issue-name-or-number>
    refactor/<description>

Examples:

  • feature/lazy-computation
  • fix/null-pointer-issue-32
  • refactor/dataframe-optimizations

After completing work on the task:

  • βœ… Create a Pull Request (PR) from the feature branch to the dev branch.
  • βœ… Conduct code review and testing.
  • βœ… After successful review, merge into dev.
  • βœ… Delete the feature branch after merging.

πŸ“Œ Hotfix Branches (Emergency Fixes):

If a serious error is discovered in a release (the main branch), we quickly fix it through a special hotfix branch from main:

  • Naming format:

    hotfix/<critical-issue>

Example:

  • hotfix/dataframe-critical-bug

After fixing:

  • βœ… Merge the hotfix branch into main.
  • βœ… Then merge main back into dev to incorporate the fixes into the development branch.

πŸ“Œ Complete Workflow Process:

main (stable)
  β”‚
  β”œβ”€ dev (development)
  β”‚   β”œβ”€ feature/lazy-computation
  β”‚   β”œβ”€ feature/arrow-integration
  β”‚   β”œβ”€ fix/null-pointer-issue-32
  β”‚   └─ refactor/dataframe-optimizations
  β”‚
  └─ hotfix/dataframe-critical-bug (if urgent fix needed)

πŸ“Š Steps Before Release (when updating main):

  1. βœ… Verify that the dev branch is fully stable and tested.
  2. βœ… Create a release PR from the dev branch to main.
  3. βœ… Conduct final review, CI/CD tests, and regression tests.
  4. βœ… Merge the PR into main.
  5. βœ… Create a git release tag (e.g., v1.0.0) to mark the stable release point.

Example:

git checkout main
git merge dev
git tag v1.0.0
git push origin main --tags

βš™οΈ Supporting Tools and Practices (Best Practices):

  • βœ… Pull Requests (PR): Perform mandatory code reviews and tests before merging.

  • βœ… Automation through CI/CD (GitHub Actions): Run automated testing, linting, and benchmarking.

  • βœ… Branch protection rules on GitHub: Protect main and dev branches from accidental direct commits. Configure mandatory PR reviews before merging.

  • βœ… Semantic Versioning (SemVer): Strictly follow semantic versioning (1.0.0, 1.1.0, 1.1.1).

πŸ“Ž Example of Semantic Versioning Approach:

  • 1.0.0 β€” first stable release.
  • 1.0.1 β€” bug fixes and minor corrections.
  • 1.1.0 β€” new features that maintain backward compatibility.
  • 2.0.0 β€” release with changes that break backward compatibility.

βœ… Daily Work Recommendations (Best Practices):

  • Commit small changes frequently with informative messages.
  • Create issues and PRs for each task.
  • Regularly merge the dev branch into your feature branches to avoid conflicts.
  • Use Squash/Merge commits for a clean history.
  • Monitor stability and test coverage through CI/CD.

πŸš€ Getting Started

  1. Fork this repo on GitHub
  2. Clone your fork locally:
    git clone git@github.com:AlphaQuantJS/tinyframejs.git
    cd tinyframejs
    npm install
  3. Create a feature branch:
    git checkout -b feat/your-feature-name
  4. Implement your feature or fix inside src/
  5. Run tests and linting before pushing (see workflow below)
  6. Push and open a Pull Request to the main branch

πŸ“ Coding Standards & Guidelines

Please review our Coding Guidelines for:

  • Performance tips for V8
  • Data integrity and numerical precision
  • Modular and reusable function design
  • Memory-efficient handling of large datasets

πŸ“‹ Pull Request Checklist

  • Code builds with pnpm build
  • Added or updated relevant tests in the appropriate package
  • Methods properly registered with extendDataFrame
  • Namespaces used for domain-specific methods
  • Follows ESLint/Prettier rules
  • Descriptive commit message (see below)
  • Linked to a GitHub Issue (if applicable)
  • Clear description in PR body of what was changed and why
  • If change is test-only or doc-only, ensure CI does not fail due to lack of coverage
  • If new code is added, ensure at least minimal test coverage is present (to trigger coverage report upload)

βœ… Steps Before Commit

1. πŸ” Check and auto-fix formatting (Prettier)

pnpm format

πŸ“Œ Automatically applies the .prettierrc style to all .js, .json, .md, .yml, etc.


2. βœ… Auto-fix code with ESLint rules

pnpm lint --fix

πŸ“Œ Fixes linting errors and style, including JSDoc, spaces, indents, no-unused-vars, etc.


3. πŸ§ͺ Run tests

pnpm test

πŸ“Œ Runs all tests (via Vitest) and checks that code is not broken.


4. πŸ§ͺ Check coverage (optional)

pnpm coverage

πŸ“Œ Generates coverage/lcov.info and prints the report to the console.


5. 🐢 (Automatically) on git commit

git add .
git commit -m "feat: describe your change"

πŸ“Œ This will automatically trigger:

  • npx lint-staged
  • npx prettier --write on staged files
  • eslint --fix on staged .js/.ts

πŸ’‘ Recommended one-liner for all:

pnpm format && pnpm lint --fix && pnpm test

🧾 Commit Message Format

We use Conventional Commits for changelogs and releases.

Format:

<type>(scope): short summary

Examples:

feat(core): add corrMatrix support
fix(frame): handle NaN edge case in rollingMean
docs(readme): add usage examples

Common types:

Type Description
feat New feature
fix Bug fix
docs Documentation-only changes
refactor Code refactor without behavioral change
test Adding or updating tests
chore Infrastructure, config, CI, etc.

πŸ”„ Best Practices

  • Keep pull requests small and focused
  • Add tests for each new piece of logic
  • Document public functions with JSDoc
  • Use dependency injection pattern for all methods
  • Register methods properly with extendDataFrame
  • Use namespaces for domain-specific methods
  • Benchmark performance-critical paths
  • Update examples/ when introducing new APIs

πŸ§ͺ Testing and Coverage

  • Run tests via pnpm test (all packages) or pnpm -F @tinyframejs/[package] test (specific package)
  • Test through the DataFrame API, not internal functions
  • Coverage is uploaded to Codecov
  • Benchmarks are located in benchmarks/
  • Guard tests protect against performance/memory regressions

🐞 Bug Reports / Feature Requests

Use GitHub Issues for:

  • Bugs and regressions
  • Feature suggestions
  • Discussion prompts

We tag beginner-friendly tasks as good first issue.


πŸ“š Documentation & Examples

  • See examples/ for real-world usage
  • Contribute examples, notebooks, articles, or benchmark comparisons!

πŸ’¬ Community & Support

  • Ask in GitHub Discussions
  • Submit new ideas via PR or Issues
  • Mention us on Twitter: @AlphaQuantJS

Thanks again for being part of the TinyFrameJS open-source journey πŸ™Œ Let's build next-gen tools for financial analysis and large-scale data processing in JavaScript together ⚑