Scaffold a new function following the fn(args, deps) pattern with Result types
Scaffolds a new TypeScript function using the fn(args, deps) pattern with Result types. Creates both the implementation file with proper error handling and a comprehensive test file with vitest mocks.
/plugin marketplace add jagreehal/jagreehal-claude-skills/plugin install jagreehal-claude-skills@jagreehal-marketplace<function-name> [description]Create a new TypeScript function named $ARGUMENTS following the jagreehal-claude-skills patterns.
Replace the following placeholders in all generated files:
FUNCTION_NAME → The function name in camelCase (e.g., getUser)FunctionName → The function name in PascalCase (e.g., GetUser)function-name → The function name in kebab-case (e.g., get-user)src/domain/function-name.ts)import type { Result } from '@jagreehal/workflow';
import { ok, err } from '@jagreehal/workflow';
// Args: per-call input data
export type FunctionNameArgs = {
// TODO: Define args based on function purpose
id: string;
};
// Deps: injected collaborators (things you'd mock in tests)
export type FunctionNameDeps = {
// TODO: Define deps (db, logger, external services)
db: Database;
logger: Logger;
};
// Explicit error types in the signature
export type FunctionNameError = 'NOT_FOUND' | 'DB_ERROR';
export async function FUNCTION_NAME(
args: FunctionNameArgs,
deps: FunctionNameDeps
): Promise<Result<unknown, FunctionNameError>> {
deps.logger.debug('FUNCTION_NAME called', { args });
try {
// TODO: Implement business logic
const result = await deps.db.find(args.id);
if (!result) {
return err('NOT_FOUND');
}
return ok(result);
} catch (error) {
deps.logger.error('FUNCTION_NAME failed', {
args,
error: error instanceof Error ? error.message : String(error),
});
return err('DB_ERROR');
}
}
src/domain/function-name.test.ts)import { describe, it, expect } from 'vitest';
import { mock } from 'vitest-mock-extended';
import { FUNCTION_NAME, type FunctionNameDeps } from './function-name';
describe('FUNCTION_NAME', () => {
it('returns ok with result when found', async () => {
// Arrange
const mockResult = { id: '123', name: 'Test' };
const deps = mock<FunctionNameDeps>();
deps.db.find.mockResolvedValue(mockResult);
// Act
const result = await FUNCTION_NAME({ id: '123' }, deps);
// Assert
expect(result.ok).toBe(true);
if (result.ok) {
expect(result.value).toEqual(mockResult);
}
});
it('returns err NOT_FOUND when not found', async () => {
// Arrange
const deps = mock<FunctionNameDeps>();
deps.db.find.mockResolvedValue(null);
// Act
const result = await FUNCTION_NAME({ id: '123' }, deps);
// Assert
expect(result.ok).toBe(false);
if (!result.ok) {
expect(result.error).toBe('NOT_FOUND');
}
});
it('returns err DB_ERROR on database failure', async () => {
// Arrange
const deps = mock<FunctionNameDeps>();
deps.db.find.mockRejectedValue(new Error('Connection failed'));
// Act
const result = await FUNCTION_NAME({ id: '123' }, deps);
// Assert
expect(result.ok).toBe(false);
if (!result.ok) {
expect(result.error).toBe('DB_ERROR');
}
});
});
mock<DepsType>() for typed mocksnpm test