@umpire/core
v1.0.0
Published
Pure field-availability logic for any state with interdependent options. No framework code, no subscriptions, no runtime dependencies.
Readme
@umpire/core
Pure field-availability logic for any state with interdependent options. No framework code, no subscriptions, no runtime dependencies.
Install
npm install @umpire/coreQuick Example
import { enabledWhen, requires, umpire } from '@umpire/core'
const signupUmp = umpire({
fields: {
email: { required: true, isEmpty: (v) => !v },
password: { required: true, isEmpty: (v) => !v },
confirmPassword: { required: true, isEmpty: (v) => !v },
companyName: {},
companySize: {},
},
rules: [
requires('confirmPassword', 'password'),
enabledWhen('companyName', (_values, ctx) => ctx.plan === 'business', {
reason: 'business plan required',
}),
enabledWhen('companySize', (_values, ctx) => ctx.plan === 'business', {
reason: 'business plan required',
}),
requires('companySize', 'companyName'),
],
})
const availability = signupUmp.check(
{ email: '[email protected]', password: 'hunter2' },
{ plan: 'business' },
)
availability.companySize
// { enabled: false, fair: true, required: false, reason: 'requires companyName', reasons: ['requires companyName'] }
const fouls = signupUmp.play(
{
values: {
email: '[email protected]',
password: 'hunter2',
companyName: 'Acme',
companySize: '50',
},
conditions: { plan: 'business' },
},
{
values: {
email: '[email protected]',
password: 'hunter2',
companyName: 'Acme',
companySize: '50',
},
conditions: { plan: 'personal' },
},
)
// [
// { field: 'companyName', reason: 'business plan required', suggestedValue: undefined },
// { field: 'companySize', reason: 'business plan required', suggestedValue: undefined },
// ]API Overview
umpire({ fields, rules })creates an instance with a validated dependency graph.ump.check(values, conditions?, prev?)returns anAvailabilityMap.ump.play(before, after)returnsFoul[].ump.init(overrides?)returns default field values.ump.challenge(field, values, conditions?, prev?)returns a debug trace for one field.ump.graph()returns the structural dependency graph.ump.rules()returns normalized runtime rule entries withid,index, and inspection metadata for debugging and test tooling.
See the docs for full type details and behavior notes: https://sdougbrown.github.io/umpire/
Rule Types
requires(field, ...dependencies)— field stays disabled until dependencies are satisfied and availableenabledWhen(field, predicate, options?)— field enabled only when a predicate returns truefairWhen(field, predicate, options?)— field's current value is appropriate only when a predicate returns truedisables(source, targets, options?)— active source disables target fieldsoneOf(groupName, branches, options?)— only one branch of fields is active at a timeanyOf(...rules)— OR logic: pass if any inner rule passeseitherOf(groupName, branches)— named OR paths where each branch is a group of ANDed rulescheck(field, validator)— bridge validators into rules with preserved field metadata
Use field<V>('name') to create a typed field reference. Pass it to fairWhen (or any rule) to get a typed value parameter instead of unknown.
Docs
https://sdougbrown.github.io/umpire/
Benchmarks
Benchmark tooling and baseline timings live in BENCHMARKS.md.
