npm package: @kaskad/schema
Description: Schema transformation and normalization library for the Kaskad framework.
Latest version: 0.0.27

# @kaskad/schema

Schema transformation and normalization library for the Kaskad framework.

## Overview

The `@kaskad/schema` library provides utilities for transforming and normalizing schema definitions in the Kaskad framework. It handles the conversion of shorthand notations and raw schemas into fully normalized `NodeSchema` structures that can be processed by the core engine.

## Key Features

- **Schema Unfolding**: Transform shorthand and compact schema notations into fully normalized structures
- **Type Parsing**: Parse complex type expressions including arrays, maps, objects, and commands
- **Wrapper Notation**: Support for component wrapper syntax with automatic slot detection
- **Property Shorthand**: Convert property key shorthands like `name@string` into full schema definitions

## Installation

```bash
npm install @kaskad/schema
```

## Usage

### Unfolding Properties

Transform property shorthands into full schema definitions:

```typescript
import { unfoldProperty } from '@kaskad/schema';

// Simple property with type annotation
const [key, schema] = unfoldProperty('name@string', 'John');
// Returns: ['name', { value: 'John', valueType: { type: 'string' }, ... }]

// Array property
const [key, schema] = unfoldProperty('items@string[]', null);
// Returns: ['items', { value: null, valueType: { type: 'array', item: { type: 'string' } }, ... }]

// Object property
const [key, schema] = unfoldProperty('user@{name:string,age:number}', null);
// Returns object type with field definitions
```

### Parsing Value Types

Parse type expressions into structured type definitions:

```typescript
import { parseValueType } from '@kaskad/schema';

// Simple types
parseValueType('string');  // { type: 'string' }
parseValueType('number');  // { type: 'number' }

// Array types
parseValueType('string[]');  // { type: 'array', item: { type: 'string' } }

// Map types
parseValueType('string{}');  // { type: 'map', item: { type: 'string' } }

// Object types
parseValueType('{name:string,age:number}');
// { type: 'object', fields: { name: { type: 'string' }, age: { type: 'number' } } }

// Command types
parseValueType('(string,number)');
// { type: 'command', args: [{ type: 'string' }, { type: 'number' }] }
```

### Schema Normalization

Convert raw schemas to full notation:

```typescript
import { toFullNotation } from '@kaskad/schema';

// Simple value
const result = toFullNotation('hello', { type: 'string' });
// Returns: { _value: 'hello', _valueType: { type: 'string' }, ... }

// Formula computation
const result = toFullNotation('=getValue()', { type: 'string' });
// Returns: { _computation: '=getValue()', _valueType: { type: 'string' }, ... }

// Conditional schema
const result = toFullNotation(
  { if: 'isActive', then: 'active', else: 'inactive' },
  { type: 'string' }
);
// Returns conditional computation structure
```

### Wrapper Notation

Handle component wrapper syntax:

```typescript
import { extractWrappers, hasWrappers, unfoldFlatWrappers } from '@kaskad/schema';

const schema = {
  '+card': { title: 'My Card' },
  '+modal': { size: 'large' },
  componentType: 'text',
  value: 'Hello'
};

// Check for wrappers
hasWrappers(schema);  // true

// Extract wrapper configuration
const [wrappers, cleanSchema] = extractWrappers(schema);
// wrappers: [['card', { title: 'My Card' }], ['modal', { size: 'large' }]]
// cleanSchema: { componentType: 'text', value: 'Hello' }

// Apply wrappers to create nested structure
const result = unfoldFlatWrappers(wrappers, cleanSchema, resultNode);
// Creates nested component structure with wrappers
```

## Type System

### Supported Value Types

- **Primitive Types**: `string`, `number`, `boolean`, `unknown`
- **Collection Types**: 
  - Arrays: `string[]`, `number[][]`
  - Maps: `string{}`, `number[]{}`
- **Structured Types**:
  - Objects: `{field1:type1,field2:type2}`
  - Commands: `(arg1Type,arg2Type)`
- **Entity Types**: Custom entity and polymorphic entity types
- **Component Type**: For component schemas

### Schema Structure

A fully normalized `NodeSchema` contains:

```typescript
interface NodeSchema {
  value: unknown;           // The actual value
  valueType: ValueType;      // Type definition
  computation: Computation;  // Formula or computation definition
  binding: BindingSchema;    // Data binding configuration
}
```

## API Reference

### Core Functions

#### `unfoldProperty(key: string, value: unknown): [string, NodeSchema]`
Transforms a property key with type annotation and value into a normalized schema.

#### `unfoldNodeSchema(value: unknown, valueType: ValueType): NodeSchema`
Unfolds a value into a complete NodeSchema based on the provided type.

#### `toFullNotation(nodeSchema: unknown, valueType: ValueType): RawNode`
Converts various schema notations into full notation format.

#### `parseValueType(type: string): ValueType`
Parses a type expression string into a structured ValueType.

#### `parsePropertyKeyShorthand(shorthand: string): [string, ValueType]`
Extracts property key and type from shorthand notation.

### Wrapper Functions

#### `hasWrappers(schema: ComponentRawSchema | TemplateRawSchema): boolean`
Checks if a schema contains wrapper notation (properties starting with '+').

#### `extractWrappers(schema: ComponentRawSchema | TemplateRawSchema): [WrapperEntity[], Schema]`
Separates wrapper configuration from the main schema.

#### `unfoldFlatWrappers(wrappers: WrapperEntity[], schema: Schema, resultNode: RawNode): RawNode`
Applies wrapper configuration to create nested component structure.

## Examples

### Complete Example: Component with Wrappers and Computed Properties

```typescript
import { unfoldProperty, toFullNotation } from '@kaskad/schema';

// Define a form input component with validation
const rawSchema = {
  '+card': { title: 'User Input' },
  componentType: 'input',
  properties: {
    'value@string': null,
    'validators@validator[]': [],
    'validity@validity': '=validate(value, validators)',
    'disabled@boolean': false
  }
};

// Process each property
const properties = {};
for (const [key, value] of Object.entries(rawSchema.properties)) {
  const [propKey, propSchema] = unfoldProperty(key, value);
  properties[propKey] = propSchema;
}

// Result: Fully normalized component schema with:
// - Typed properties
// - Computed validity based on validators
// - Wrapper configuration for card display
```

## Running Tests

This library was generated with [Nx](https://nx.dev).

Run `nx test schema` to execute the unit tests.

## License

Part of the Kaskad framework.