UNPKG

go-go-try

Version:

Tries to execute a sync/async function, returns a result tuple

241 lines (186 loc) 8.32 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](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()`