npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@kotaio/adaptive-requirements-engine

v1.0.0

Published

Schema-driven requirements engine with JSON Logic rules for conditional evaluation, validation, and computed fields

Readme

@kotaio/adaptive-requirements-engine

Framework-agnostic engine for evaluating requirement schemas returned by the Adaptive Requirements API. Handles field visibility, validation, computed values, option resolution, and multi-step flow navigation — with zero React or browser dependencies.

When to use this package

  • Server-side validation — evaluate the same schemas on the server for parity with client-side validation
  • Non-React renderers — build custom form renderers in any framework
  • Custom integrations — use the engine functions directly for advanced workflows

If you're building a React application, use @kotaio/adaptive-form instead — it wraps this engine with a ready-made component.

Installation

npm install @kotaio/adaptive-requirements-engine

Core concepts

Requirement schemas are returned by the API as RequirementsObject values. A schema contains:

  • Fields — input definitions with types, labels, validation rules, and conditional behavior
  • Datasets — reusable option lists that fields can reference
  • Flow (optional) — step definitions for multi-step forms with conditional navigation

The engine provides pure functions to evaluate these schemas against the current form data. You never need to construct schemas yourself — they come from the API.

API

Field state

checkField(requirements, fieldId, data, options?)

The primary function. Returns the complete runtime state for a single field: visibility, required status, validation errors, resolved options, computed value, and label.

import { checkField } from '@kotaio/adaptive-requirements-engine';

const state = checkField(requirements, 'date_of_birth', formData);

state.isVisible; // boolean — should this field be rendered?
state.isRequired; // boolean — is this field currently required?
state.isReadOnly; // boolean — should this field be read-only?
state.isExcluded; // boolean — should this field be excluded from submission?
state.errors; // string[] — validation error messages
state.value; // current field value (from data or computed)
state.options; // ResolvedFieldOption[] | undefined — resolved select/radio options
state.label; // string | undefined — resolved label text
state.field; // the field definition from the schema

calculateData(requirements, data)

Returns computed field values only. Use this to update the form data after a field change.

import { calculateData } from '@kotaio/adaptive-requirements-engine';

const computed = calculateData(requirements, formData);
// { subtotal: 150, tax: 15, total: 165 }

Cascading logic

When a field value changes, it can affect the visibility or exclusion of other fields. These functions iterate until stable.

clearHiddenFieldValues(requirements, data)

Clears values for fields whose visibleWhen rule evaluates to false. Iterates because hiding field A may hide field B.

import { clearHiddenFieldValues } from '@kotaio/adaptive-requirements-engine';

const cleaned = clearHiddenFieldValues(requirements, formData);

applyExclusions(requirements, data)

Clears values for fields whose excludeWhen rule evaluates to true. Same cascading behavior as above.

import { applyExclusions } from '@kotaio/adaptive-requirements-engine';

const filtered = applyExclusions(requirements, formData);

Options

resolveFieldOptions(field, datasets?, context?, labelResolver?)

Resolves a field's options — either from inline options or from a referenced dataset via optionsSource. Supports dynamic filtering against current form data.

import { resolveFieldOptions } from '@kotaio/adaptive-requirements-engine';

const options = resolveFieldOptions(field, requirements.datasets, { data: formData });
// [{ value: 'us', label: 'United States' }, { value: 'ca', label: 'Canada' }]

Rule evaluation

runRule(rule, context)

Evaluates a JSON Logic expression against a data context. Used internally by the engine, but available for custom rule evaluation.

import { runRule } from '@kotaio/adaptive-requirements-engine';

const result = runRule({ '>=': [{ var: 'age' }, 18] }, { data: formData });
// true or false

Labels

resolveLabel(label, locale?)

Resolves a localized label to a plain string. Labels can be simple strings or objects with a default value and an optional i18n key.

import { resolveLabel } from '@kotaio/adaptive-requirements-engine';

resolveLabel('First Name'); // 'First Name'
resolveLabel({ default: 'First Name', key: 'fields.first_name' }); // 'First Name'

Validation

runCustomValidators(value, validators, context, customValidators?)

Runs an array of validators against a field value. Returns an array of error message strings (empty if valid). Checks built-in validators first, then falls back to any custom validators you provide.

import { runCustomValidators } from '@kotaio/adaptive-requirements-engine';

const errors = runCustomValidators(
  '1990-01-01',
  [{ type: 'dob_not_in_future' }, { type: 'age_range', params: { min: 18, max: 100 } }],
  { data: formData },
);
// [] (valid) or ['Must be at least 18 years old']

builtInValidators

A record of built-in validator functions:

| Validator | Params | Description | | ------------------- | ------------ | ---------------------------------------------------- | | age_range | min, max | Validates age calculated from a date is within range | | dob_not_in_future | — | Date must not be in the future | | date_after | date | Date must be after the specified date | | date_before | date | Date must be before the specified date | | spanish_tax_id | — | Validates Spanish NIF/NIE format | | irish_pps | — | Validates Irish PPS number format | | german_tax_id | — | Validates German Steuer-ID (11 digits) | | file_type | accept | File extension/MIME type matching | | file_size | maxSize | File size limit in bytes | | file_count | maxFiles | Maximum number of files |

validateRequirementsObject(input)

Structural validation for a requirements schema. Returns a ValidationResult with either the validated object or an array of errors. Useful for verifying API responses or testing.

import { validateRequirementsObject } from '@kotaio/adaptive-requirements-engine';

const result = validateRequirementsObject(schema);
if (result.success) {
  // result.data is the validated RequirementsObject
} else {
  // result.errors is ValidationError[]
  // each error has { path: string, message: string }
}

validateDatasetItems(input)

Validates an array of dataset items. Same ValidationResult return shape.

Flow navigation

When a schema includes a flow, these functions handle step progression.

getInitialStepId(flow, options?)

Returns the starting step ID. When options.requirements and options.formData are provided, skips steps with no visible fields.

getNextStepId(flow, currentStepId, data, options?)

Returns the next step ID. Evaluates navigation rules first (for conditional step skipping), then falls back to sequential order. Skips steps with no visible fields.

getPreviousStepId(flow, currentStepId)

Returns the previous step ID (sequential only).

stepHasVisibleFields(requirements, stepId, data, options?)

Returns true if the given step has at least one visible field. Used to skip empty steps during navigation.

Adapter

createAdapter(requirements, mapping?, options?)

Creates a bundled adapter object that wraps the engine functions with an optional field ID mapping. Useful when your consumer's field naming conventions differ from the schema's.

import { createAdapter } from '@kotaio/adaptive-requirements-engine';

const adapter = createAdapter(requirements, {
  fieldIdMap: { firstName: 'first_name', lastName: 'last_name' },
});

// Now use adapter.checkField, adapter.calculateData, etc.
// They automatically translate between your field IDs and the schema's

JSON Logic reference

Schemas use JSON Logic expressions for conditional visibility, conditional validation, computed values, and dataset filtering. The engine evaluates these automatically — this reference is for understanding what schemas can express.

Variables

{ var: 'fieldName' }          // Access a field's current value
{ var: 'data.fieldName' }     // Explicit data access (equivalent)
{ var: 'answers.fieldName' }  // Alias for data access
{ var: 'item.property' }      // Access a dataset item property (used in filters)

Operators

Comparison: ==, !=, >, <, >=, <=, in

Logical: and, or, !

Conditional: ?: (ternary), if (if-then-else)

Math: +, -, *, /, %, max, min, abs

String: cat (concatenate), substr

Custom date operations

The engine registers these additional operations for date handling:

| Operation | Description | | ----------------------------------- | ------------------------------------------ | | { today: {} } | Current date as YYYY-MM-DD | | { age_from_date: <date> } | Age in whole years from a date | | { months_since: <date> } | Months elapsed since a date | | { date_diff: { from, to, unit } } | Difference in days, months, or years | | { abs: <number> } | Absolute value |

Key types

Key types exported for use in custom integrations:

| Type | Description | | --------------------- | ---------------------------------------------------------------------------- | | RequirementsObject | Top-level schema: fields, datasets, and optional flow | | Field | Single field definition: id, type, label, validation, visibility rules, etc. | | FieldState | Runtime state for a field: visibility, errors, value, options | | FormData | Record<string, FieldValue> — the current form data | | FieldValue | string \| number \| boolean \| null \| undefined or array thereof | | Rule | A JSON Logic expression | | Dataset | A named list of items that fields can reference | | Flow | Step definitions and optional navigation rules | | FieldMapping | Field ID remapping configuration | | EngineOptions | Options for custom validators, locale, and label resolution | | ValidationResult | { success: true, data } \| { success: false, errors } | | ValidationError | { path: string, message: string } | | ResolvedFieldOption | { value: string \| boolean, label: string } |

License

Apache-2.0 — see LICENSE for details.