Skip to content

Latest commit

 

History

History
240 lines (186 loc) · 8.12 KB

File metadata and controls

240 lines (186 loc) · 8.12 KB

go-go-try - Agent Guide

Project Overview

go-go-try is a TypeScript utility library for error handling inspired by Go's error handling pattern. It provides a functional approach to try/catch operations by returning a tuple [error, value] instead of throwing exceptions.

  • Name: go-go-try
  • Version: 7.2.1
  • License: MIT
  • Repository: thelinuxlich/go-go-try
  • Node.js Requirements: >= 16

Key Features

  • Zero runtime dependencies
  • Dual package support (CommonJS and ESM)
  • Full TypeScript support with precise type inference
  • Support for sync/async functions, promises, and direct values
  • Parallel execution utilities with optional concurrency control
  • Tagged errors for discriminated union pattern matching

Technology Stack

  • Language: TypeScript 5.9.3
  • Build Tool: pkgroll - A zero-config TypeScript package bundler
  • Linter: Biome - Fast linter and formatter
  • Test Framework: Vitest - Vite-native unit test framework
  • Type Testing: @ark/attest - Runtime type assertions for TypeScript
  • Git Hooks: Husky + lint-staged

Project Structure

.
├── src/
│   ├── index.ts        # Main source file - exports all functions and types
│   └── index.test.ts   # Comprehensive test suite with runtime and type tests
├── dist/               # Build output (generated by pkgroll)
│   ├── index.cjs       # CommonJS build
│   ├── index.mjs       # ES Module build
│   ├── index.d.cts     # CommonJS type definitions
│   └── index.d.mts     # ES Module type definitions
├── .github/workflows/
│   └── main.yml        # CI configuration for GitHub Actions
├── .husky/
│   └── pre-commit      # Git pre-commit hook (runs lint-staged)
├── .attest/            # Ark attest cache directory
├── package.json        # Package configuration with dual CJS/ESM exports
├── tsconfig.json       # TypeScript strict configuration
├── vitest.config.ts    # Vitest configuration with type checking and coverage
├── setupVitest.ts      # Vitest global setup for @ark/attest
└── README.md           # User-facing documentation

Build and Test Commands

# Build the project (generates dist/ with CJS, ESM, and type definitions)
npm run build

# Run linting with auto-fix
npm run lint

# Run the full test suite (build + lint + vitest)
npm test

# Run tests with coverage report
npm run test:coverage

The npm test script is a composite that:

  1. Builds the project
  2. Runs the linter
  3. Executes Vitest tests with type checking

Code Style Guidelines

  • Linter: Biome is used for linting and formatting with default configuration (no biome.json present)
  • Pre-commit: Husky runs lint-staged which lints all staged .ts files via Biome
  • Strict TypeScript: The tsconfig.json enforces strict mode with additional checks:
    • noUnusedLocals: true
    • noUnusedParameters: true
    • allowUnreachableCode: false
    • noUncheckedIndexedAccess: true
    • noFallthroughCasesInSwitch: true
    • forceConsistentCasingInFileNames: true

Testing Instructions

Test Structure

Tests are co-located with source code in src/index.test.ts using Vitest.

Test Types

  1. Runtime Tests: Standard unit tests verifying behavior using Vitest's assert and test
  2. Type Tests: Using @ark/attest to verify TypeScript type inference at runtime with attest<T>(value)

Key Testing Patterns

// Runtime test
import { assert, test } from 'vitest'
test('description', () => {
  const result = goTry(() => 'value')
  assert.equal(result[1], 'value')
})

// Type test
import { attest } from '@ark/attest'
test('types are correct', () => {
  const result = goTry('value')
  attest<Result<string, string>>(result)
})

Running Tests

# Run all tests with type checking
npx vitest run

# Run tests in watch mode (during development)
npx vitest

# Run with coverage
npx vitest run --coverage

Coverage Configuration

Coverage is provided by @vitest/coverage-v8 with reporters: text, json, html, and lcov. Excluded paths:

  • node_modules/
  • dist/
  • **/*.test.ts
  • setupVitest.ts

API Design

Core Functions

Function Description Error Type
goTry<T>(value) Returns [string | undefined, T | undefined] Error message string
goTryRaw<T, E>(value, ErrorClass?) Returns [E | undefined, T | undefined] Raw Error object or tagged error
goTryOr<T>(value, defaultValue) Returns [string | undefined, T] Error message with fallback default
goTryAll<T>(items, options?) Parallel execution, returns [errors[], results[]] Error message strings
goTryAllRaw<T>(items, options?) Parallel execution, returns [Error[], results[]] Raw Error objects

Input Handling

All goTry* functions accept:

  • Direct values
  • Functions (sync or async)
  • Promises

Type Helpers

  • Result<E, T>: The tuple type [E \| undefined, T \| undefined]
  • Success<T>: [undefined, T]
  • Failure<E>: [E, undefined]
  • TaggedError<T>: Interface for discriminated errors with _tag property
  • TaggedUnion<T>: Creates union type from multiple tagged error classes
  • isSuccess(result): Type guard to check if result is success
  • isFailure(result): Type guard to check if result is failure
  • success(value): Helper to create Success tuple
  • failure(error): Helper to create Failure tuple

Tagged Errors

The taggedError(tag) function creates error classes with a _tag property for discriminated union pattern matching:

const DatabaseError = taggedError('DatabaseError')
const err = new DatabaseError('connection failed')
// err._tag === 'DatabaseError'
// err instanceof Error === true

Dual Package Support

The package supports both CommonJS and ESM consumers:

{
  "type": "module",
  "main": "./dist/index.cjs",
  "module": "./dist/index.mjs",
  "types": "./dist/index.d.mts",
  "exports": {
    "require": { "types": "./dist/index.d.cts", "default": "./dist/index.cjs" },
    "import": { "types": "./dist/index.d.mts", "default": "./dist/index.mjs" }
  }
}

CI/CD

GitHub Actions workflow (.github/workflows/main.yml):

Test Job

  • Runs on every push and PR to main/master
  • Tests against Node.js versions: 18, 20, 22
  • Steps: checkout → setup Node → install → build → test with coverage
  • fail-fast: false to see results for all Node versions
  • Coverage uploaded to Codecov (Node 22 only)

Publish Job

  • Runs only on tag pushes (refs/tags/v*)
  • Depends on successful test job
  • Publishes to npm with provenance
  • Requires NPM_TOKEN secret

Security Considerations

  • Zero runtime dependencies - reduces supply chain attack surface
  • Dev dependencies are locked via package-lock.json
  • Uses type: "module" for native ESM support
  • npm publishing uses provenance for supply chain security
  • CI has minimal permissions (contents: read, id-token: write)

Development Workflow

  1. Make changes to src/index.ts
  2. Add/update tests in src/index.test.ts
  3. Run npm test to verify build, lint, and tests pass
  4. The CI will test against multiple Node.js versions on push
  5. To release: push a version tag (e.g., v7.2.1) to trigger npm publish

Notes for AI Agents

  • Always run npm test after making changes to ensure build, lint, and tests pass
  • Type tests with @ark/attest are as important as runtime tests
  • The library has zero dependencies - avoid adding any
  • Maintain dual CJS/ESM compatibility when making changes
  • Follow the existing function overload patterns for type inference
  • Error handling should preserve the Go-style tuple return pattern
  • Use taggedError() for creating discriminated error types
  • The goTryAll function supports both promise arrays and factory function arrays for lazy execution
  • When adding new functions, include both runtime tests and type tests with attest()