Skip to content

Latest commit

 

History

History
144 lines (114 loc) · 7.14 KB

File metadata and controls

144 lines (114 loc) · 7.14 KB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Build and Test Commands

  • npm start - Start development server (IMPORTANT: Never run this command directly; ask the user to start the server as needed)
  • npm run build - Build production version
  • npm run lint - Run ESLint
  • npm run lint-fix - Run ESLint with auto-fix
  • npm run format - Run Prettier
  • npm run test - Run all tests
  • npm run test:unit - Run unit tests
  • npm run test:integration - Run integration tests
  • npm run test:cpu - Run CPU compatibility tests
  • npm run ci-checks - Run linting checks for CI
  • vitest run tests/unit/test-gzip.js - Run a single test file

Code Coverage

  • npm run coverage:unit - Run unit tests with coverage
  • npm run coverage:all-tests - Run all tests with coverage
  • Coverage reports are generated in the coverage directory
  • HTML report includes line-by-line coverage visualization

Code Style Guidelines

  • Formatting: Uses Prettier, configured in package.json
  • Linting: ESLint with eslint-config-prettier integration
  • Modules: ES modules with import/export syntax (type: "module")
  • JavaScript Target: ES2020 with strict null checks
  • Error Handling: Use try/catch with explicit error messages that provide context about what failed
  • Naming: camelCase for variables and functions, PascalCase for classes
  • Imports: Group by source (internal/external) with proper separation
  • Documentation: Use JSDoc for public APIs and complex functions, add comments for non-obvious code
  • Error Messages: Use consistent, specific error messages (e.g., "Track buffer overflow" instead of "Overflow in disc building")

Test Organization

  • Test Consolidation: All tests for a specific component should be consolidated in a single test file. For example, all tests for emulator.js should be in test-emulator.js - do not create separate test files for different aspects of the same component.
  • Test Structure: Use nested describe blocks to organize tests by component features
  • Test Isolation: When mocking components in tests, use vi.spyOn() with vi.restoreAllMocks() in afterEach hooks rather than global vi.mock() to prevent memory leaks and test pollution
  • Memory Management: Avoid global mocks that can leak between tests and accumulate memory usage over time
  • Test philosophy
    • Mock as little as possible: Try and rephrase code not to require it.
    • Try not to rely on internal state: don't manipulate objects' inner state in tests
    • Use idiomatic vitest assertions (expect/toBe/toEqual) instead of node assert

Project-Specific Knowledge

  • Never commit code unless asked: Very often we'll work on code and iterate. After you think it's complete, let me check it before you commit.

Code Architecture

  • General Principles:

    • Follow the existing code style and structure
    • Use const and let instead of var
    • Avoid global variables; use module scope
    • Use arrow functions for callbacks
    • Prefer template literals over string concatenation
    • Use destructuring for objects and arrays when appropriate
    • Use async/await for asynchronous code instead of callbacks or promises
    • Minimise special case handling - prefer explicit over implicit behaviour
    • Consider adding tests first before implementing features
  • When simplifying existing code

    • Prefer helper functions for repetitive operations (like the appendParam function)
    • Remove unnecessary type checking where types are expected to be correct
    • Replace complex conditionals with more readable alternatives when possible
    • Ensure simplifications don't break existing behavior or assumptions
    • Try and modernise the code to use ES6+ features where possible
  • Prefer helper functions for repetitive operations (like the appendParam function)

  • Remove unnecessary type checking where types are expected to be correct

  • Replace complex conditionals with more readable alternatives when possible

  • Ensure simplifications don't break existing behavior or assumptions

  • Constants and Magic Numbers:

    • Local un-exported properties should be used for shared constants
    • Local constants should be used for temporary values
    • Always use named constants instead of magic numbers in code
    • Use PascalCase for module-level constants (e.g., const MaxHfeTrackPulses = 3132;)
    • Prefer module-level constants over function-local constants for shared values
    • Define constants at the beginning of functions or at the class/module level as appropriate
    • Add comments explaining what the constant represents, especially for non-obvious values
  • Pre-commit Hooks:

    • The project uses lint-staged with ESLint
    • Watch for unused variables and ensure proper error handling
    • YOU MUST NEVER bypass git commit hooks on checkins. This leads to failures in CI later on

Save State / Snapshots

  • The snapshot JSON format is documented in docs/snapshot-format.mdkeep it up to date if you add new fields to any component's snapshotState() or change the format version
  • Each component owns its own snapshotState() / restoreState() methods
  • Scheduler tasks are not serialized directly — each component saves its task offset relative to scheduler.epoch and re-registers on restore
  • interrupt is not saved in the CPU snapshot — it is reconstructed by VIA/ACIA restoreState() calls
  • soundChip.lastRunEpoch is always synced to the scheduler epoch on restore, not saved

Git Workflow

  • When creating branches with Claude, use the claude/ prefix (e.g., claude/fix-esm-import-error)

Conventional Commits

This project uses Conventional Commits for automated versioning and changelog generation via release-please.

Commit types for user-facing changes (appear in changelog, affect version):

  • fix: - Bug fixes (bumps patch version: 0.0.7 → 0.0.8)
  • feat: - New features (bumps minor version: 0.0.7 → 0.1.0)
  • fix!: or feat!: - Breaking changes (bumps major version: 0.0.7 → 1.0.0)

Commit types for internal changes (do NOT appear in changelog, do NOT affect version):

  • chore: - Maintenance tasks, tooling updates, dependency updates
  • ci: - CI/CD configuration changes (GitHub Actions, etc.)
  • build: - Build system changes (webpack, vite, electron-builder config)
  • docs: - Documentation-only changes
  • style: - Code style changes (formatting, whitespace)
  • refactor: - Code refactoring without behavior change
  • test: - Test additions or modifications

Guidelines:

  • Use fix: and feat: ONLY for changes that affect end users
  • Use chore:, ci:, or build: for internal tooling/infrastructure changes
  • Example: A release-please workflow fix should be ci: or chore:, not fix:
  • Breaking changes must include BREAKING CHANGE: in the commit body or use ! (e.g., feat!:)

Examples:

fix: enable window scaling in Electron app
feat: add joystick support for gamepads
chore: update dependencies to latest versions
ci: fix release-please workflow configuration
build: configure electron-builder icon settings
docs: update README with installation instructions