Skip to content

API Reference

Terminal window
npm install holey
Terminal window
dotnet add package Holey

Marks an incomplete part of the program with a description. Optionally accepts a temporary implementation to keep the program running.

ParameterTypeDescription
descriptionstringWhat this hole represents or what needs to be done here
implementationT | (() => T) | Promise<T> | (() => Promise<T>)Optional temporary stand-in

If no implementation is provided, the return type is never — compatible with any position in your code.

ParameterTypeDescription
descriptionstringWhat this hole represents or what needs to be done here
implementationTValue, Func<TValue>, Task<TValue>, or Func<Task<TValue>>Optional temporary stand-in

C# exposes multiple overloads rather than a single generic signature:

Hole.Todo(string description)
TValue Hole.Todo<TValue>(string description, TValue value)
TValue Hole.Todo<TValue>(string description, Func<TValue> factory)
Task<TValue> Hole.Todo<TValue>(string description, Task<TValue> task)
Task<TValue> Hole.Todo<TValue>(string description, Func<Task<TValue>> factory)
Task Hole.Todo(string description, Task task)
function deleteAccount(userId: string): Promise<void> {
return hole("delete account and all associated data")
}

Calling this throws HoleNotImplementedError: delete account and all associated data.

public Task DeleteAccount(string userId)
{
return Hole.Todo("delete account and all associated data");
}

Calling this throws HoleNotImplementedException: delete account and all associated data.

const config = hole("load config from remote", { timeout: 5000, retries: 3 })
var config = Hole.Todo("load config from remote", new Config { Timeout = 5000, Retries = 3 });
const apiKey = hole("read API_KEY from secrets manager", () => process.env.API_KEY ?? "")
var apiKey = Hole.Todo(
"read API_KEY from secrets manager",
() => Environment.GetEnvironmentVariable("API_KEY")
);
const user = await hole("fetch user from database", async () => {
return { id: "1", name: "Alice" }
})
var user = await Hole.Todo(
"fetch user from database",
Task.FromResult(new User { Id = 1, Name = "Alice" })
);
const result = await hole(
"process payment",
hole("select payment provider", stripeProvider).charge(order)
)
var result = await Hole.Todo(
"process payment",
Hole.Todo("select payment provider", stripeProvider).ChargeAsync(order)
);

import { configure } from 'holey'
configure({
onHole: (info) => {
console.warn(`[hole] ${info.description} (${info.file}:${info.line})`)
},
mode: 'warn', // 'warn' | 'throw' | 'silent'
})
OptionTypeDefaultDescription
mode'warn' | 'throw' | 'silent''warn'What happens when a hole without an implementation is reached
onHole(info: HoleInfo) => voidundefinedCalled every time any hole is evaluated
Holes
.UseLoggerFactory(loggerFactory)
.UseReporting(reporter => reporter.OnHoleEncountered(info => Console.WriteLine(info)))
.UseExtensions(extensions => extensions.AddSidecar());
MethodDescription
.UseLoggerFactory(factory)Route Holey’s internal logs through .NET’s ILoggerFactory
.UseReporting(configure)Register runtime reporters for hole events
.UseExtensions(configure)Register extensions such as the Sidecar application

FieldTypeDescription
descriptionstringThe hole’s description string
filestringSource file path
linenumberLine number of the hole call
hasImplementationbooleanWhether a temporary implementation was provided

Holey for C# collects hole metadata at both compile time (via Roslyn analyzers and source generators) and runtime (via CallerFilePath, CallerLineNumber, and stack frames):

FieldSourceDescription
DescriptionRuntimeThe hole’s description string
Location.FilePathCompile-timeSource file path
Location.LineNumberCompile-timeLine number
Location.ColumnNumberRuntime (stack frame, debug only)Column number
ExpressionLiteralCompile-timeSource text of the implementation expression
ReturnTypeCompile-timeType of the value the hole returns

HoleNotImplementedError is thrown when a hole without an implementation is reached at runtime:

HoleNotImplementedError: delete account and all associated data
at hole (holey/index.js:12:11)
at deleteAccount (src/users.ts:42:10)

HoleNotImplementedException is thrown when an empty Hole.Todo() is reached at runtime:

Holey.HoleNotImplementedException: delete account and all associated data
at Holey.Hole.Todo(String description) in Hole.cs:line 18
at UserService.DeleteAccount(String userId) in UserService.cs:line 42

For NotImplementedException (the built-in C# type), Holey’s Roslyn analyzer reports it as a compile-time warning so it surfaces before you hit runtime.


Holey’s Roslyn analyzers surface all hole types in the IDE Error List:

Hole typeSyntaxCodeDebug severityRelease severity
Todo Comment// TODO: …HLY101WarningError
Hole Comment// TODO [Tag]: …HLY201InformationWarning
Missing Implementationthrow new NotImplementedException(…)HLY102WarningError
Side EffectHole.Todo(…)HLY301InformationWarning

Add <TreatWarningsAsErrors>true</TreatWarningsAsErrors> to your release build configuration to prevent any holes from shipping to production.