Thank you for your interest in contributing to AzerothJS! Every contribution matters — whether it's fixing a typo, reporting a bug, or implementing a new feature.
- Node.js 20+
- npm 10+
- TypeScript 6+
git clone https://github.com/IntelligentQuantum-Dev/AzerothJS.git
cd AzerothJS
npm install| Command | Description |
|---|---|
npm run build |
Compile TypeScript |
npm run dev |
Compile in watch mode |
npm test |
Run tests with Vitest |
src/
├── reactivity/ # Signals, effects, memos, batch, untrack, etc.
├── renderer/ # h(), render(), Show, For, Switch, Portal, etc.
├── component/ # defineComponent, AzerothComponent, lifecycle
├── core/ # Shared utilities (future)
├── router/ # Official router (future)
├── store/ # Global store (future)
├── compiler/ # .azeroth compiler (future)
└── index.ts # Public API entry point
test/ # Mirrors src/ structure
demo/ # Interactive demo app
- Brace style: Allman (opening brace on its own line)
- Indentation: 4 spaces
- Quotes: Single quotes
- Semicolons: Always
- Line endings: LF (Unix)
ESLint is configured to enforce these rules. Run your editor's ESLint integration or check manually:
npx eslint src/- Functions:
camelCase—createSignal,createEffect - Types/Interfaces:
PascalCase—Subscriber,SignalOptions - Constants:
UPPER_SNAKE_CASE—DOM_PROPERTIES - Files:
kebab-case—create-root.ts,on-cleanup.ts - Internal exports: Prefixed with
@internalin JSDoc
- Write complete JSDoc for every public function, type, and interface
- Include
@param,@returns, and at least one@example - Add educational comments explaining WHY, not just WHAT
- Keep functions small and focused
- No external runtime dependencies
Every feature must have tests. We use Vitest with happy-dom.
# Run all tests
npm test
# Run a specific test file
npx vitest run test/reactivity/signal.test.ts
# Run in watch mode
npx vitestTest file location: Mirror the source structure under test/.
src/reactivity/signal.ts → test/reactivity/signal.test.ts
src/renderer/show.ts → test/renderer/show.test.ts
src/component/types.ts → test/component/types.test.ts
Test structure:
import { describe, it, expect } from 'vitest';
import { createSignal } from '../../src/index.ts';
describe('createSignal', () =>
{
it('should return initial value', () =>
{
const [count] = createSignal(0);
expect(count()).toBe(0);
});
});Use clear, descriptive commit messages:
feat: add createSelector for efficient list selection
fix: prevent memory leak in effect cleanup
test: add tests for createDeferred debounce behavior
docs: update API reference for onCleanup
refactor: simplify batch queue flushing logic
Open an issue with:
- Description — What happened vs what you expected
- Reproduction — Minimal code that demonstrates the bug
- Environment — Node version, OS, browser (if applicable)
Open an issue with:
- Use case — What problem does this solve?
- Proposed API — How should it look?
- Alternatives — What other approaches did you consider?
- Fork the repository
- Create a feature branch:
git checkout -b feat/my-feature - Write your code with tests
- Ensure all tests pass:
npm test - Submit a pull request with a clear description
- Code follows the project's style guidelines
- JSDoc is added for all public APIs
- Tests are added and passing
- No breaking changes (or clearly documented if intentional)
- Commit messages are clear and descriptive
AzerothJS uses fine-grained reactivity with zero Virtual DOM:
- Signals hold reactive state
- Effects subscribe to signals and re-run on changes
- The renderer (
h()) creates real DOM elements and wires up effects for reactive attributes and children - Components (
defineComponent/AzerothComponent) provide structure, props, and lifecycle
There is no diffing, no reconciliation, no virtual nodes. When a signal changes, only the specific DOM nodes that depend on it are updated directly.
By contributing, you agree that your contributions will be licensed under the MIT License.