Skip to content

Kimesh Code Standards & Guidelines

Version: 0.2.23 Effective: January 28, 2026 Scope: All packages in /packages/, /modules/, and /tooling/ directories

Overview

This document establishes coding standards, conventions, and best practices for the Kimesh monorepo. All contributions must adhere to these guidelines to maintain consistency, readability, and maintainability across the codebase.

File Organization

Directory Structure

Each package follows this standard structure:

packages/package-name/
├── src/
│   ├── index.ts                    # Main export file
│   ├── types.ts                    # Type definitions
│   ├── [feature-name]/
│   │   ├── index.ts                # Feature export
│   │   ├── [implementation].ts      # Implementation details
│   │   └── [implementation].test.ts # Tests
│   ├── [feature].ts                # Single-file features
│   ├── [feature].test.ts           # Feature tests
│   └── utils/                      # Shared utilities
│       ├── index.ts
│       └── [utility].ts
├── package.json                    # Package metadata
├── tsconfig.json                   # TypeScript config
├── tsdown.config.ts                # Build config
├── README.md                       # Package documentation
├── augment.d.ts                    # Vue type augmentation (optional)
└── .test/                          # Test fixtures (optional)

Module Definition Pattern

Modules in /modules/ follow the same structure with additional:

  • src/module.ts - Module configuration/factory
  • src/plugin.ts - Plugin definition
  • augment.d.ts - Framework augmentation

File Naming

  • Directories: kebab-case

    ✓ src/route-generator/
    ✓ src/auto-import/
    ✗ src/routeGenerator/
    ✗ src/autoImport/
  • Files: kebab-case

    ✓ route-merger.ts
    ✓ oxc-scanner.ts
    ✓ conflict-resolver.ts
    ✗ routeMerger.ts
    ✗ oxcScanner.ts
  • Test Files: [name].test.ts

    ✓ route-merger.ts + route-merger.test.ts
    ✓ plugin.ts + plugin.test.ts
    ✗ route-merger-test.ts
    ✗ route-merger.spec.ts
  • Private/Internal Files: Leading underscore

    ✓ _internal-helpers.ts
    ✓ _shared-utils.ts
    ✗ internal-helpers.ts (if not exported)
  • Type Definition Files: types.ts

    ✓ src/types.ts (type definitions)
    ✓ src/types/config.ts (organized types)
    ✗ src/types.ts + src/interfaces.ts (mixed naming)
  • Index Files: Always index.ts

    ✓ src/index.ts
    ✓ src/feature/index.ts
    ✗ src/main.ts
    ✗ src/feature/main.ts

File Size & Complexity

Size Limits

  • Maximum 200 lines per file (soft limit, hard stops at 250)
  • Rationale: Improves readability, easier testing, clearer responsibility
  • Exceptions: Test files may exceed with complex test suites, but split when over 300 lines

Complexity Guidelines

  • Maximum cyclomatic complexity: 10
  • Maximum nesting depth: 4 levels
  • Maximum function length: 50 lines (aim for 20-30)
  • Maximum parameters: 4 (use objects for 5+)

Metrics

typescript
// ✓ Good: Clear responsibility, single purpose
export function generateRoute(config: RouteConfig): Route {
  // ~20 lines
}

// ✗ Poor: Too many responsibilities
export function generateAndValidateAndOptimizeAndSerialize(
  config: RouteConfig,
  validation: boolean,
  optimize: boolean,
  format: string,
): Route {
  // ~200 lines of mixed concerns
}

TypeScript Standards

Strict Mode Required

All packages must have TypeScript strict mode enabled:

json
{
  "compilerOptions": {
    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "strictFunctionTypes": true,
    "strictBindCallApply": true,
    "strictPropertyInitialization": true,
    "noImplicitThis": true,
    "alwaysStrict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true
  }
}

Type Definitions

Always export types from types.ts:

typescript
// src/types.ts
export interface RouteConfig {
  path: string
  component?: Component
  meta?: Record<string, any>
}

export interface Route extends RouteConfig {
  children?: Route[]
  id: string
}

// src/router-generator.ts
import type { RouteConfig, Route } from './types'

export function generateRoute(config: RouteConfig): Route {
  // ...
}

Use specific types, not any:

typescript
// ✓ Good
function processRoute(route: Route): string {
  return route.path
}

// ✗ Poor
function processRoute(route: any): any {
  return route.path
}

Use unknown instead of any for flexibility:

typescript
// ✓ Good for generic handlers
function handle(data: unknown): void {
  if (typeof data === 'string') {
    // ...
  }
}

// ✗ Poor
function handle(data: any): void {
  // ...
}

Naming Conventions

Functions & Variables

  • camelCase for all functions and variables

    typescript
    export function generateRoutes() {}
    const routeConfig = {}
    let currentIndex = 0
  • PascalCase for classes and components

    typescript
    export class RouteGenerator {}
    export const KmHead = defineComponent({})
    const MyComponent = () => {}
  • UPPER_SNAKE_CASE for constants

    typescript
    export const MAX_FILE_SIZE = 1024 * 1024
    const DEFAULT_TIMEOUT_MS = 5000
  • Interfaces: PascalCase, optional I prefix

    typescript
    interface RouteDefinition {}
    interface IKimeshConfig {}
    type RouteOptions = {}
  • Imports: Match export naming

    typescript
    import { RouteGenerator } from './generator'
    import type { RouteConfig } from './types'
    import { MAX_FILE_SIZE } from './constants'

Vue Components

  • PascalCase for component names

    typescript
    export const KmHead = defineComponent({})
    export const KmLink = defineComponent({})
    export const kmHead = defineComponent({})
  • kebab-case for component files

    ✓ src/components/km-head.ts
    ✓ src/components/km-link.ts
    ✗ src/components/KmHead.ts
    ✗ src/components/kmHead.ts

Import/Export Patterns

Export Order

Organize exports in this order:

typescript
// 1. Type-only exports first
export type { RouteConfig, Route, RouteDefinition }

// 2. Interface exports
export interface { RouterContext }

// 3. Constant exports
export const MAX_ROUTES = 1000
export const DEFAULT_TIMEOUT = 5000

// 4. Function exports
export function generateRoute(config: RouteConfig): Route {}
export function validateRoute(route: Route): boolean {}

// 5. Class exports
export class RouteGenerator {
  // ...
}

// 6. Re-exports from other modules
export * from './utils'
export * from './helpers'

Named Exports Only

Avoid default exports for consistency:

typescript
// ✓ Good: Named exports
export function generateRoute() {}
export interface RouteConfig {}
export class RouteGenerator {}

// Later: Selective imports
import { generateRoute, RouteGenerator } from './route-generator'

// ✗ Poor: Default exports
export default function generateRoute() {}
export default class RouteGenerator {}

// Later: Unclear what is exported
import generateRoute from './route-generator'

Exception: Main index.ts files may have appropriate re-exports.

Path Aliases

Use path aliases from tsconfig.json:

typescript
// ✓ Good
import type { RouteConfig } from '@kimesh/kit/types'
import { generateRoute } from '@/route-generator'

// ✗ Poor (relative paths in deeply nested files)
import type { RouteConfig } from '../../../../../../../types'
import { generateRoute } from '../../route-generator'

Type-Only Imports

Always use type keyword for type imports:

typescript
// ✓ Good: Tree-shaking aware
import type { RouteConfig, Route } from './types'
import { generateRoute } from './generator'

// ✗ Poor: Unnecessary runtime imports
import { RouteConfig, Route } from './types'

Testing Standards

Test Coverage Requirements

  • Minimum coverage: 90% across all packages
  • Core packages (kit, router-generator, auto-import): 95%+
  • Integration tests: Required for major features

Test File Organization

typescript
// route-merger.test.ts
import { describe, it, expect, beforeEach } from 'vitest'
import { mergeRoutes } from './route-merger'
import type { Route } from './types'

describe('mergeRoutes', () => {
  let routes: Route[]

  beforeEach(() => {
    routes = []
  })

  describe('basic functionality', () => {
    it('should merge simple routes', () => {
      // Arrange
      const route1: Route = { path: '/', id: '1' }
      const route2: Route = { path: '/about', id: '2' }

      // Act
      const result = mergeRoutes([route1, route2])

      // Assert
      expect(result).toHaveLength(2)
    })

    it('should preserve route order', () => {
      // ...
    })
  })

  describe('edge cases', () => {
    it('should handle empty array', () => {
      // ...
    })

    it('should handle duplicate paths', () => {
      // ...
    })
  })
})

Test Naming Conventions

  • Test files: [feature].test.ts
  • Describe blocks: Feature or context name
  • Test cases: Start with verb (should, must, handles)
typescript
// ✓ Good
describe('RouteGenerator', () => {
  it('should generate valid routes from config', () => {})
  it('should throw error for invalid path', () => {})
  it('handles nested routes correctly', () => {})
})

// ✗ Poor
describe('test route generation', () => {
  it('works', () => {})
  it('error handling', () => {})
})

Mocking Patterns

typescript
// Use vi.mock() for module mocking
import { vi, describe, it, expect } from 'vitest'

vi.mock('./dependency', () => ({
  getDependency: vi.fn().mockReturnValue({}),
}))

// Use vi.fn() for function mocking
const mockFn = vi.fn()
mockFn.mockReturnValue('value')
mockFn.mockImplementation((arg) => arg * 2)

Module Definition Standards

Package.json Structure

json
{
  "name": "@kimesh/package-name",
  "version": "0.2.23",
  "description": "Clear, concise description of package purpose",
  "repository": {
    "type": "git",
    "url": "https://github.com/kimeshjs/kimesh.git"
  },
  "type": "module",
  "exports": {
    ".": {
      "types": "./dist/index.d.ts",
      "import": "./dist/index.js"
    }
  },
  "main": "./dist/index.js",
  "types": "./dist/index.d.ts",
  "files": ["dist", "types.d.ts"],
  "scripts": {
    "build": "tsdown",
    "dev": "tsdown --watch",
    "test": "vitest run"
  },
  "dependencies": {
    "@kimesh/other-package": "workspace:*"
  },
  "devDependencies": {
    "typescript": "^5.8.3",
    "tsdown": "^0.20.0-beta.3"
  },
  "peerDependencies": {
    "vue": "^3.5.0"
  }
}

Module Export Structure

typescript
// src/index.ts - Main entry point
export * from './types'
export * from './feature1'
export * from './feature2'
export * from './utils'

// src/types.ts - All type definitions
export interface ModuleConfig {}
export type ModuleOptions = {}

// src/feature.ts - Single feature
export function feature() {}

// src/feature/index.ts - Complex feature
export * from './implementation'
export * from './helpers'

Error Handling

Error Types

Use specific error classes:

typescript
// ✓ Good: Specific error types
export class InvalidRouteError extends Error {
  constructor(
    message: string,
    public route: Route,
  ) {
    super(message)
    this.name = 'InvalidRouteError'
  }
}

export class ConfigValidationError extends Error {
  constructor(
    message: string,
    public config: unknown,
  ) {
    super(message)
    this.name = 'ConfigValidationError'
  }
}

// Usage
if (!isValidRoute(route)) {
  throw new InvalidRouteError('Route path is invalid', route)
}

Error Messages

  • Clear and actionable: Describe what went wrong and why
  • Include context: Show the problematic values
  • Suggest fixes: When possible, indicate how to resolve
typescript
// ✓ Good
throw new Error(
  `Invalid route path "${route.path}". ` + `Expected route path to start with "/" but got "${route.path.charAt(0)}".`,
)

// ✗ Poor
throw new Error('Bad route')
throw new Error('Route error')

Documentation Standards

Function Documentation

Use JSDoc for all public functions:

typescript
/**
 * Generates route configuration from file-based structure.
 *
 * @param config - The route configuration object
 * @param options - Optional generation options
 * @returns Generated route object with nested children
 * @throws {InvalidRouteError} If the configuration is invalid
 *
 * @example
 * ```typescript
 * const route = generateRoute({ path: '/' })
 * ```
 */
export function generateRoute(config: RouteConfig, options?: GenerationOptions): Route {
  // ...
}

Type Documentation

Document complex types and interfaces:

typescript
/**
 * Configuration options for route generation.
 *
 * @property path - The route path (required, must start with /)
 * @property component - Vue component for the route (optional)
 * @property meta - Route metadata for middleware/guards (optional)
 * @property children - Nested routes (optional)
 */
export interface RouteConfig {
  path: string
  component?: Component
  meta?: Record<string, any>
  children?: RouteConfig[]
}

Code Formatting

Format & Lint Configuration

The project uses automated formatting and linting:

  • Formatter: oxfmt (Rust-based)
  • Linter: oxlint (Rust-based)
  • Run before commit: pnpm fmt && pnpm lint:fix

Commands:

bash
# Check formatting
pnpm fmt:check

# Auto-format
pnpm fmt

# Check linting
pnpm lint

# Fix linting issues
pnpm lint:fix

# Full validation
pnpm fmt:check && pnpm lint && pnpm typecheck

Indentation & Style

  • Indent: 2 spaces (enforced by oxfmt)
  • Line length: 100 characters (soft), 120 (hard)
  • Semicolons: Required (enforced by oxlint)
  • Trailing commas: ES5-style (enforced by oxfmt)

Performance Considerations

Build Performance

  • Use tree-shaking compatible exports (named exports)
  • Avoid circular dependencies
  • Minimize runtime overhead from generated code
  • Use lazy imports for optional features

Runtime Performance

  • Cache computed values when appropriate
  • Minimize re-renders in Vue components
  • Use composition API for optimal tree-shaking
  • Avoid inline function definitions in templates

Version Management

Versioning Scheme

Kimesh follows semantic versioning:

MAJOR.MINOR.PATCH (e.g., 0.2.23)
- MAJOR: Breaking API changes
- MINOR: New features, backward compatible
- PATCH: Bug fixes, backward compatible

Dependency Updates

  • Use workspace:* for internal monorepo dependencies
  • Pin exact versions for external dependencies in package.json
  • Update dependencies monthly during development
  • Security updates immediately

Code Review Checklist

Before submitting a PR, verify:

  • [ ] All files follow naming conventions
  • [ ] No file exceeds 200 lines (except tests/docs)
  • [ ] TypeScript strict mode passes
  • [ ] Test coverage >= 90%
  • [ ] All tests pass: pnpm test
  • [ ] Code formatted: pnpm fmt
  • [ ] Linting passes: pnpm lint
  • [ ] Type checking passes: pnpm typecheck
  • [ ] Documentation updated
  • [ ] Error messages are clear and actionable
  • [ ] No console.log statements (use proper logging)
  • [ ] No commented-out code

Continuous Enforcement

These standards are enforced by:

  1. Pre-commit hooks (when configured)
  2. GitHub Actions CI (pull request checks)
  3. Code review process (manual verification)
  4. Automated tooling (oxfmt, oxlint, Vitest)

All contributions must pass these checks before merging.

Released under the MIT License.