@formos/schema
v0.1.0
Published
JSON schema definitions for the Formos form builder
Maintainers
Readme
@formos/schema
Pure TypeScript type definitions for the Formos form builder.
Purpose
@formos/schema defines the structure of form schemas using TypeScript types and interfaces. It provides the vocabulary for describing forms declaratively as JSON, enabling type-safe form configuration that can be serialized, stored, and transmitted.
Responsibilities
This package is responsible for:
- Type Definitions: Defining TypeScript types for form schemas (
FormSchemaV1,FieldSchema,ValidationSchema, etc.) - Schema Normalization: Converting raw schemas into optimized runtime structures with computed properties (
normalizeSchema()) - Version Management: Supporting multiple schema versions with deprecation tracking
- Validation Triggers: Defining when validations should execute (
onChange,onBlur,onSubmit) - Conditional Logic: Describing dynamic field visibility and requirements
- Type Guards: Providing utility functions to check schema types at runtime
What This Package Does NOT Do
❌ NO Runtime Execution
- Does not manage form state (values, errors, touched fields)
- Does not execute validation logic
- Does not trigger effects or side effects
- Does not render UI components
❌ NO Framework Dependencies
- No React, Vue, or any UI framework
- No validation libraries (Zod, Yup, etc.)
- No DOM or browser APIs
❌ NO Business Logic
- Does not contain validation rules
- Does not implement effect handlers
- Does not execute conditional logic
Think of it as: The blueprint/contract for forms, not the engine that runs them.
Stability Guarantee
Schema v1 is IMMUTABLE and FINAL ✅
Once published, FormSchemaV1 will never have breaking changes:
- Field names won't change
- Required properties won't become optional (or vice versa)
- Type definitions won't change structure
This guarantee enables:
- Safe serialization: Schemas can be stored as JSON and loaded years later
- Version compatibility: Old schemas will always work with new kernel versions
- Predictable behavior: No surprises when upgrading dependencies
What Can Change
✅ New optional properties may be added (always backward compatible)
✅ New helper functions can be added to exports
✅ Internal implementation of normalizeSchema() can be optimized
✅ New schema versions (v2, v3) can be added without affecting v1
Deprecation Process
If a property or function needs to be phased out:
- Mark with
@deprecatedJSDoc tag - Provide migration guidance in documentation
- Maintain support for at least 2 major versions
- Use
registerVersion()to track deprecated schema versions
Installation
pnpm add @formos/schemaBasic Usage
Define a Form Schema
import { FormSchemaV1, CURRENT_VERSION } from '@formos/schema';
const schema: FormSchemaV1 = {
version: CURRENT_VERSION,
fields: [
{
name: 'email',
type: 'email',
label: 'Email Address',
required: true,
validations: [
{
trigger: ['onChange', 'onBlur'],
validator: 'email',
rule: {},
message: 'Please enter a valid email'
}
]
},
{
name: 'age',
type: 'number',
label: 'Age',
required: { field: 'country', operator: 'equals', value: 'US' },
visibleWhen: { field: 'showAge', operator: 'equals', value: true }
}
]
};Normalize for Runtime Use
import { normalizeSchema } from '@formos/schema';
// Normalize adds computed properties for efficient runtime access
const normalized = normalizeSchema(schema);
// Pass to kernel for execution
import { createFormEngine } from '@formos/kernel';
const engine = createFormEngine(normalized);Work with Validation Triggers
import {
normalizeTriggers,
shouldValidateOnTrigger,
type ValidationSchema
} from '@formos/schema';
const validation: ValidationSchema = {
trigger: ['onChange', 'onBlur'],
validator: 'required',
rule: {}
};
// Check if validation should run on a specific trigger
if (shouldValidateOnTrigger(validation, 'onChange')) {
console.log('Validate on change');
}
// Normalize trigger to array
const triggers = normalizeTriggers('onSubmit'); // ['onSubmit']Type Guards for Conditional Logic
import {
isConditionalRule,
isConditionalGroup,
hasConditionalRequired
} from '@formos/schema';
const field: FieldSchema = {
name: 'ssn',
type: 'text',
required: { field: 'country', operator: 'equals', value: 'US' }
};
if (hasConditionalRequired(field)) {
// TypeScript knows field.required is Conditional
if (isConditionalRule(field.required)) {
console.log(`Required when ${field.required.field} is US`);
}
}Multi-Step Forms
import { FormSchemaV1, StepSchema } from '@formos/schema';
const multiStepSchema: FormSchemaV1 = {
version: 'v1',
fields: [
{ name: 'firstName', type: 'text' },
{ name: 'lastName', type: 'text' },
{ name: 'email', type: 'email' },
{ name: 'phone', type: 'tel' }
],
steps: [
{
id: 'personal',
title: 'Personal Information',
fields: ['firstName', 'lastName']
},
{
id: 'contact',
title: 'Contact Details',
fields: ['email', 'phone']
}
]
};API Reference
Core Types
FormSchemaV1: Complete form schema with version, fields, steps, effectsFieldSchema: Single field definition with type, validation, effectsNormalizedSchemaV1: Optimized schema with field map and indexesValidationSchema: Declarative validation rule configurationEffectSchema: Side effect triggered by field changesConditional: Dynamic visibility and required logic
Functions
normalizeSchema(input): Validate and optimize schema for runtimenormalizeTriggers(trigger): Normalize triggers to array formatshouldValidateOnTrigger(validation, trigger): Check if validation appliesisSupportedVersion(version): Type guard for schema versionsgetVersionInfo(version): Get version metadata- Type Guards:
isConditionalRule,isConditionalGroup,hasConditionalRequired,hasVisibilityCondition
Version Management
CURRENT_VERSION: Latest schema version (currently "v1")SUPPORTED_VERSIONS: Array of all supported versionsSchemaVersion: @deprecated Legacy constant, useCURRENT_VERSION
Package Structure
@formos/schema/
├── version.ts # Version management and registry
├── field.ts # Field type definitions
├── validation.ts # Validation schema types
├── effects.ts # Effect schema types
├── conditional.ts # Conditional logic types
├── step.ts # Multi-step schema types
├── form.ts # Root form schema type
├── normalize.ts # Schema normalization
├── guards.ts # Type guard utilities
├── errors.ts # SchemaValidationError
└── index.ts # Public API exportsTypeScript Configuration
This package uses strict mode TypeScript:
noUncheckedIndexedAccess: truemoduleResolution: "NodeNext"module: "NodeNext"
All exports are ESM only (type: "module").
Integration with @formos/kernel
import { normalizeSchema, type FormSchemaV1 } from '@formos/schema';
import { createFormEngine } from '@formos/kernel';
// 1. Define schema (JSON-serializable)
const schema: FormSchemaV1 = { /* ... */ };
// 2. Normalize once
const normalized = normalizeSchema(schema);
// 3. Create engine (can reuse normalized schema)
const engine = createFormEngine(normalized, {
validators: { /* custom validators */ },
effectExecutors: { /* custom effects */ }
});
// 4. Use engine API (see @formos/kernel docs)
await engine.setValue('email', '[email protected]');
const isValid = await engine.validate();Contributing
This package is part of the Formos monorepo. See the root README for contribution guidelines.
License
MIT
