# 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](https://github.com/privatenumber/pkgroll) - A zero-config TypeScript package bundler
- **Linter**: [Biome](https://biomejs.dev/) - Fast linter and formatter
- **Test Framework**: [Vitest](https://vitest.dev/) - Vite-native unit test framework
- **Type Testing**: [@ark/attest](https://github.com/arktypeio/arktype) - Runtime type assertions for TypeScript
- **Git Hooks**: [Husky](https://typicode.github.io/husky/) + [lint-staged](https://github.com/lint-staged/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

```bash
# 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

```typescript
// 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

```bash
# 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:

```typescript
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:

```json
{
  "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()`
