@gymbile/wpl-validator
v1.7.1
Published
Reference TypeScript validator for WPL (Wellness Plan Language) — JSON Schema + semantic invariants
Readme
@gymbile/wpl-validator
Reference TypeScript validator for WPL (Wellness Plan Language).
Validates compiled WPL JSON against:
- Pass 1: the canonical JSON Schema (Draft 2020-12, via ajv).
- Pass 2: semantic invariants from the WPL specification — duplicate-ID detection, ref resolution, prescription validity, etc.
Sister implementation: wpl_validator (Elixir). Both pass the shared conformance suite at every release.
Install
npm install @gymbile/wpl-validatorRequires Node.js >= 20.10.
Usage
import { validate, type ValidationResult, type ValidationError } from '@gymbile/wpl-validator';
const plan = JSON.parse(planJson);
const result: ValidationResult = validate(plan);
if (!result.valid) {
for (const err of result.errors) {
console.error(`[${err.code}] ${err.path}: ${err.message}`);
}
}ValidationError shape
interface ValidationError {
path: string; // RFC 6901 JSON Pointer, e.g. "/plan/phases/0/weeks/1/days/2"
code: string; // e.g. "DUPLICATE_ID"
message: string; // human-readable summary
severity: 'error' | 'warning';
meta?: Record<string, unknown>; // structured detail (rule-specific keys)
}With a catalog (resolves *_ref fields)
const result = validate(plan, {
catalog: {
exercises: new Set(['push_up', 'squat', 'deadlift']),
meals: new Set(['oatmeal', 'chicken_breast']),
},
});If no catalog is provided, UNRESOLVED_REF checks are skipped.
Severity semantics
result.valid is true unless at least one finding has severity: "error". Findings with severity: "warning" (currently only PHASE_DURATION_MISMATCH) appear in result.errors but do not invalidate the plan — they're advisory.
If you want to reject warnings too, filter the result yourself:
const hasAny = result.errors.length > 0;Pipeline
The validator runs two passes in sequence:
- Pass 1 (schema): ajv compiles the canonical JSON Schema and checks the input against it. Failures emit
SCHEMA_VIOLATION. - Pass 2 (semantic): a structural walker descends the plan tree (
plan → phases → weeks → days → blocks → activities, plus personalization rules, checkpoints, and points rules). Each registered rule visits the relevant nodes and emits findings.
If Pass 1 fails, Pass 2 is skipped — semantic checks assume schema-valid shape.
Error codes
| Code | Severity | Description |
|---|---|---|
| SCHEMA_VIOLATION | error | Pass 1 ajv check failed (shape, type, enum, required field, etc.) |
| DUPLICATE_ID | error | Two siblings within the same scope share an id |
| UNRESOLVED_REF | error | An exercise_ref / meal_ref / meditation_ref doesn't exist in the supplied catalog |
| EMPTY_PHASES_FOR_TYPE | error | Plan type: "workout" or "hybrid" has zero phases |
| INVALID_PRESCRIPTION | error | Activity prescription has unknown type or missing required fields |
| INVALID_PERSONALIZATION_RULE | error | Personalization rule has malformed condition or invalid action type/scope |
| INVALID_POINTS_RULE | error | Points-system rule missing action/points or points not a non-negative integer |
| PHASE_DURATION_MISMATCH | warning | Phase declares duration: { value, unit } that doesn't match weeks.length |
Canonical reference (with meta.reason enums and JSON Pointer rules): error-codes.md.
Conformance
Vendored schema and conformance suite from gymbile/[email protected]. The conformance suite (3 valid + 10 invalid fixtures) is run on every CI build via npm test. The suite itself is not shipped to npm; see the upstream conformance directory.
A weekly drift-check workflow flags any divergence between the vendored copies in this repo and the latest upstream tag.
Contributing
See CONTRIBUTING.md for dev setup, the rule-addition recipe, and release flow.
License
Apache-2.0. See LICENSE.
Trademark
"WPL" and "Wellness Plan Language" are trademarks of Gymbile. See the schema repo for naming policy.
