# Расширенная система типизированных элементов

Система типизированных элементов CSElement предоставляет мощную типизацию на основе схем с поддержкой наследования, валидации во время выполнения и полной интеграции с TypeScript.

## 🎯 Основные возможности

### Схемы и типизация
- **JSON Schema 7** - полная поддержка стандарта
- **Runtime валидация** - проверка типов во время выполнения
- **TypeScript интеграция** - автогенерация типов
- **Наследование схем** - множественное наследование

### Валидация и ограничения
- **Поле-уровневая валидация** - индивидуальные правила для полей
- **Кросс-поле валидация** - проверка связей между полями
- **Асинхронная валидация** - поддержка внешних проверок
- **Пользовательские валидаторы** - расширяемая система

### Вычисляемые поля
- **Computed properties** - автоматически вычисляемые значения
- **Зависимости** - отслеживание изменений связанных полей
- **Кэширование** - оптимизация производительности
- **Асинхронные вычисления** - поддержка Promise

## 🚀 Быстрый старт

### Базовая настройка

```typescript
import { TypedElementManager, Schema } from 'cs-element';

// Создание менеджера типизированных элементов
const manager = new TypedElementManager({
  strictMode: true,
  enableValidation: true,
  enableInheritance: true,
  cacheSchemas: true
});

// Определение базовой схемы
const userSchema: Schema = {
  $id: 'User',
  type: 'object',
  properties: {
    id: { type: 'string', format: 'uuid' },
    name: { type: 'string', minLength: 1, maxLength: 100 },
    email: { type: 'string', format: 'email' },
    age: { type: 'integer', minimum: 0, maximum: 150 },
    isActive: { type: 'boolean', default: true }
  },
  required: ['id', 'name', 'email'],
  additionalProperties: false
};

// Регистрация схемы
manager.registerSchema(userSchema);
```

### Создание типизированных элементов

```typescript
// Создание элемента с валидацией
const user = await manager.createElement('User', {
  id: '123e4567-e89b-12d3-a456-426614174000',
  name: 'John Doe',
  email: 'john@example.com',
  age: 30
});

// Типобезопасный доступ к полям
const userName: string = user.getField('name');
const userAge: number = user.getField('age');
const isActive: boolean = user.getField('isActive'); // Использует default значение

// Обновление с валидацией
await user.setField('age', 31); // ✅ Валидно
// await user.setField('age', -5); // ❌ Ошибка валидации
// await user.setField('name', ''); // ❌ Ошибка: слишком короткое имя

console.log('Пользователь создан:', {
  id: user.id,
  data: user.getData(),
  isValid: user.isValid()
});
```

### Наследование схем

```typescript
// Базовая схема
const entitySchema: Schema = {
  $id: 'Entity',
  type: 'object',
  properties: {
    id: { type: 'string', format: 'uuid' },
    createdAt: { type: 'string', format: 'date-time' },
    updatedAt: { type: 'string', format: 'date-time' }
  },
  required: ['id']
};

// Схема с наследованием
const productSchema: Schema = {
  $id: 'Product',
  extends: ['Entity'], // Наследование от Entity
  type: 'object',
  properties: {
    name: { type: 'string', minLength: 1 },
    price: { type: 'number', minimum: 0 },
    category: { type: 'string' },
    inStock: { type: 'boolean', default: true }
  },
  required: ['name', 'price']
};

manager.registerSchema(entitySchema);
manager.registerSchema(productSchema);

// Создание продукта с унаследованными полями
const product = await manager.createElement('Product', {
  id: crypto.randomUUID(),
  createdAt: new Date().toISOString(),
  name: 'Laptop',
  price: 999.99,
  category: 'Electronics'
});

// Доступ к унаследованным полям
console.log('Продукт:', {
  id: product.getField('id'), // Из Entity
  name: product.getField('name'), // Из Product
  createdAt: product.getField('createdAt') // Из Entity
});
```

## 📚 Подробное руководство

### Продвинутые схемы

#### Вложенные объекты и массивы

```typescript
const orderSchema: Schema = {
  $id: 'Order',
  type: 'object',
  properties: {
    id: { type: 'string' },
    customer: {
      type: 'object',
      properties: {
        name: { type: 'string' },
        email: { type: 'string', format: 'email' }
      },
      required: ['name', 'email']
    },
    items: {
      type: 'array',
      items: {
        type: 'object',
        properties: {
          productId: { type: 'string' },
          quantity: { type: 'integer', minimum: 1 },
          price: { type: 'number', minimum: 0 }
        },
        required: ['productId', 'quantity', 'price']
      },
      minItems: 1
    },
    total: { type: 'number', minimum: 0 },
    status: {
      type: 'string',
      enum: ['pending', 'confirmed', 'shipped', 'delivered', 'cancelled']
    }
  },
  required: ['id', 'customer', 'items', 'total', 'status']
};

manager.registerSchema(orderSchema);

const order = await manager.createElement('Order', {
  id: 'ORD-001',
  customer: {
    name: 'Alice Johnson',
    email: 'alice@example.com'
  },
  items: [
    { productId: 'PROD-1', quantity: 2, price: 29.99 },
    { productId: 'PROD-2', quantity: 1, price: 15.50 }
  ],
  total: 75.48,
  status: 'pending'
});

// Работа с вложенными данными
const customerName = order.getField('customer.name');
const firstItemQuantity = order.getField('items.0.quantity');
```

#### Условная валидация

```typescript
const conditionalSchema: Schema = {
  $id: 'ConditionalUser',
  type: 'object',
  properties: {
    type: { type: 'string', enum: ['individual', 'business'] },
    name: { type: 'string' },
    companyName: { type: 'string' },
    taxId: { type: 'string' }
  },
  required: ['type', 'name'],
  // Условная валидация
  if: { properties: { type: { const: 'business' } } },
  then: { required: ['companyName', 'taxId'] },
  else: { not: { anyOf: [{ required: ['companyName'] }, { required: ['taxId'] }] } }
};

manager.registerSchema(conditionalSchema);

// Бизнес пользователь - требует companyName и taxId
const businessUser = await manager.createElement('ConditionalUser', {
  type: 'business',
  name: 'John Smith',
  companyName: 'Acme Corp',
  taxId: '123456789'
});

// Индивидуальный пользователь - не требует бизнес поля
const individualUser = await manager.createElement('ConditionalUser', {
  type: 'individual',
  name: 'Jane Doe'
});
```

### Валидация и ограничения

#### Пользовательские валидаторы

```typescript
// Регистрация пользовательских валидаторов
manager.registerValidator('strongPassword', {
  validate: (value: string) => {
    const hasUpper = /[A-Z]/.test(value);
    const hasLower = /[a-z]/.test(value);
    const hasNumber = /\d/.test(value);
    const hasSpecial = /[!@#$%^&*(),.?":{}|<>]/.test(value);
    const isLongEnough = value.length >= 8;
    
    return hasUpper && hasLower && hasNumber && hasSpecial && isLongEnough;
  },
  message: 'Пароль должен содержать заглавные и строчные буквы, цифры, спецсимволы и быть не менее 8 символов'
});

manager.registerValidator('uniqueEmail', {
  validate: async (value: string, context) => {
    // Асинхронная проверка уникальности
    const existingUser = await database.findUserByEmail(value);
    return !existingUser || existingUser.id === context.elementId;
  },
  message: 'Email уже используется другим пользователем',
  async: true
});

// Схема с пользовательскими валидаторами
const secureUserSchema: Schema = {
  $id: 'SecureUser',
  type: 'object',
  properties: {
    email: { 
      type: 'string', 
      format: 'email',
      'x-validator': 'uniqueEmail' // Пользовательский валидатор
    },
    password: { 
      type: 'string',
      'x-validator': 'strongPassword'
    }
  },
  required: ['email', 'password']
};
```

#### Кросс-поле валидация

```typescript
const eventSchema: Schema = {
  $id: 'Event',
  type: 'object',
  properties: {
    startDate: { type: 'string', format: 'date-time' },
    endDate: { type: 'string', format: 'date-time' },
    title: { type: 'string' },
    maxParticipants: { type: 'integer', minimum: 1 },
    currentParticipants: { type: 'integer', minimum: 0 }
  },
  required: ['startDate', 'endDate', 'title'],
  // Кросс-поле валидация
  'x-validators': [
    {
      name: 'dateRange',
      validate: (data) => new Date(data.endDate) > new Date(data.startDate),
      message: 'Дата окончания должна быть позже даты начала'
    },
    {
      name: 'participantLimit',
      validate: (data) => !data.currentParticipants || data.currentParticipants <= data.maxParticipants,
      message: 'Количество участников не может превышать максимум'
    }
  ]
};

manager.registerSchema(eventSchema);

// Создание события с валидацией
const event = await manager.createElement('Event', {
  startDate: '2024-06-01T10:00:00Z',
  endDate: '2024-06-01T18:00:00Z',
  title: 'Конференция разработчиков',
  maxParticipants: 100,
  currentParticipants: 85
});
```

### Вычисляемые поля

#### Простые вычисляемые поля

```typescript
const invoiceSchema: Schema = {
  $id: 'Invoice',
  type: 'object',
  properties: {
    items: {
      type: 'array',
      items: {
        type: 'object',
        properties: {
          quantity: { type: 'number' },
          price: { type: 'number' }
        }
      }
    },
    taxRate: { type: 'number', default: 0.1 },
    // Вычисляемые поля
    subtotal: {
      type: 'number',
      'x-computed': {
        dependencies: ['items'],
        compute: (data) => {
          return data.items.reduce((sum, item) => sum + (item.quantity * item.price), 0);
        }
      }
    },
    tax: {
      type: 'number',
      'x-computed': {
        dependencies: ['subtotal', 'taxRate'],
        compute: (data) => data.subtotal * data.taxRate
      }
    },
    total: {
      type: 'number',
      'x-computed': {
        dependencies: ['subtotal', 'tax'],
        compute: (data) => data.subtotal + data.tax
      }
    }
  },
  required: ['items']
};

manager.registerSchema(invoiceSchema);

const invoice = await manager.createElement('Invoice', {
  items: [
    { quantity: 2, price: 50 },
    { quantity: 1, price: 30 }
  ],
  taxRate: 0.15
});

// Вычисляемые поля обновляются автоматически
console.log('Счет:', {
  subtotal: invoice.getField('subtotal'), // 130
  tax: invoice.getField('tax'),           // 19.5
  total: invoice.getField('total')        // 149.5
});

// При изменении items вычисляемые поля пересчитываются
await invoice.setField('items', [
  { quantity: 3, price: 50 },
  { quantity: 2, price: 30 }
]);

console.log('Обновленный счет:', {
  subtotal: invoice.getField('subtotal'), // 210
  total: invoice.getField('total')        // 241.5
});
```

#### Асинхронные вычисляемые поля

```typescript
const enrichedUserSchema: Schema = {
  $id: 'EnrichedUser',
  type: 'object',
  properties: {
    userId: { type: 'string' },
    email: { type: 'string', format: 'email' },
    // Асинхронное вычисляемое поле
    profile: {
      type: 'object',
      'x-computed': {
        dependencies: ['userId'],
        async: true,
        compute: async (data) => {
          // Загрузка профиля из внешнего API
          const response = await fetch(`/api/users/${data.userId}/profile`);
          return response.json();
        },
        cache: true,
        ttl: 300000 // Кэш на 5 минут
      }
    },
    permissions: {
      type: 'array',
      'x-computed': {
        dependencies: ['userId'],
        async: true,
        compute: async (data) => {
          const response = await fetch(`/api/users/${data.userId}/permissions`);
          return response.json();
        }
      }
    }
  },
  required: ['userId', 'email']
};

manager.registerSchema(enrichedUserSchema);

const enrichedUser = await manager.createElement('EnrichedUser', {
  userId: 'user123',
  email: 'user@example.com'
});

// Асинхронное получение вычисляемых полей
const profile = await enrichedUser.getFieldAsync('profile');
const permissions = await enrichedUser.getFieldAsync('permissions');

console.log('Обогащенный пользователь:', {
  email: enrichedUser.getField('email'),
  profile,
  permissions
});
```

## ⚙️ Конфигурация и оптимизация

### Настройка менеджера

```typescript
const manager = new TypedElementManager({
  // Режим строгой типизации
  strictMode: true,
  
  // Валидация
  enableValidation: true,
  validateOnCreate: true,
  validateOnUpdate: true,
  
  // Наследование
  enableInheritance: true,
  maxInheritanceDepth: 10,
  
  // Производительность
  cacheSchemas: true,
  cacheComputedFields: true,
  lazyComputeFields: true,
  
  // Вычисляемые поля
  computedFieldTimeout: 5000,
  enableAsyncComputed: true,
  
  // События
  enableEvents: true,
  
  // Отладка
  debug: false,
  logValidationErrors: true
});
```

### Кэширование и производительность

```typescript
// Настройка кэширования для схем
manager.configureCaching({
  schemaCache: {
    enabled: true,
    maxSize: 1000,
    ttl: 3600000 // 1 час
  },
  computedFieldCache: {
    enabled: true,
    maxSize: 5000,
    ttl: 300000 // 5 минут
  },
  validationCache: {
    enabled: true,
    maxSize: 2000,
    ttl: 60000 // 1 минута
  }
});

// Предварительная компиляция схем
await manager.precompileSchemas(['User', 'Product', 'Order']);

// Оптимизация для массовых операций
manager.enableBatchMode(true);

const users = await Promise.all([
  manager.createElement('User', userData1),
  manager.createElement('User', userData2),
  manager.createElement('User', userData3)
]);

manager.enableBatchMode(false);
```

## 🔍 Продвинутые возможности

### Миграции схем

```typescript
// Версионирование схем
const userSchemaV1: Schema = {
  $id: 'User',
  version: '1.0.0',
  type: 'object',
  properties: {
    name: { type: 'string' },
    email: { type: 'string' }
  }
};

const userSchemaV2: Schema = {
  $id: 'User',
  version: '2.0.0',
  type: 'object',
  properties: {
    firstName: { type: 'string' },
    lastName: { type: 'string' },
    email: { type: 'string' },
    phone: { type: 'string' }
  },
  // Миграция с предыдущей версии
  'x-migration': {
    from: '1.0.0',
    migrate: (oldData) => ({
      firstName: oldData.name.split(' ')[0] || '',
      lastName: oldData.name.split(' ')[1] || '',
      email: oldData.email,
      phone: ''
    })
  }
};

// Регистрация схем с версиями
manager.registerSchema(userSchemaV1);
manager.registerSchema(userSchemaV2);

// Автоматическая миграция при загрузке старых данных
const migratedUser = await manager.loadElement({
  schemaId: 'User',
  version: '1.0.0',
  data: { name: 'John Doe', email: 'john@example.com' }
});

console.log('Мигрированный пользователь:', migratedUser.getData());
// { firstName: 'John', lastName: 'Doe', email: 'john@example.com', phone: '' }
```

### Полиморфизм

```typescript
// Базовая схема для полиморфизма
const shapeSchema: Schema = {
  $id: 'Shape',
  type: 'object',
  discriminator: { propertyName: 'type' },
  oneOf: [
    { $ref: '#/definitions/Circle' },
    { $ref: '#/definitions/Rectangle' },
    { $ref: '#/definitions/Triangle' }
  ],
  definitions: {
    Circle: {
      type: 'object',
      properties: {
        type: { const: 'circle' },
        radius: { type: 'number', minimum: 0 }
      },
      required: ['type', 'radius']
    },
    Rectangle: {
      type: 'object',
      properties: {
        type: { const: 'rectangle' },
        width: { type: 'number', minimum: 0 },
        height: { type: 'number', minimum: 0 }
      },
      required: ['type', 'width', 'height']
    },
    Triangle: {
      type: 'object',
      properties: {
        type: { const: 'triangle' },
        base: { type: 'number', minimum: 0 },
        height: { type: 'number', minimum: 0 }
      },
      required: ['type', 'base', 'height']
    }
  }
};

manager.registerSchema(shapeSchema);

// Создание полиморфных объектов
const circle = await manager.createElement('Shape', {
  type: 'circle',
  radius: 5
});

const rectangle = await manager.createElement('Shape', {
  type: 'rectangle',
  width: 10,
  height: 8
});

// Типобезопасная работа с полиморфными объектами
function calculateArea(shape: TypedElement): number {
  const shapeType = shape.getField('type');
  
  switch (shapeType) {
    case 'circle':
      const radius = shape.getField('radius');
      return Math.PI * radius * radius;
    case 'rectangle':
      const width = shape.getField('width');
      const height = shape.getField('height');
      return width * height;
    case 'triangle':
      const base = shape.getField('base');
      const triangleHeight = shape.getField('height');
      return 0.5 * base * triangleHeight;
    default:
      throw new Error(`Неизвестный тип фигуры: ${shapeType}`);
  }
}

console.log('Площади:', {
  circle: calculateArea(circle),
  rectangle: calculateArea(rectangle)
});
```

### TypeScript интеграция

```typescript
// Автогенерация TypeScript типов
import { TypeScriptGenerator } from 'cs-element';

const generator = new TypeScriptGenerator();

// Генерация типов из схем
const typeDefinitions = generator.generateTypes([
  userSchema,
  productSchema,
  orderSchema
]);

console.log('Сгенерированные типы:');
console.log(typeDefinitions.code);

// Сохранение в файл
import fs from 'fs';
fs.writeFileSync('generated-types.d.ts', typeDefinitions.code);

// Использование сгенерированных типов
interface GeneratedUser {
  id: string;
  name: string;
  email: string;
  age?: number;
  isActive?: boolean;
}

// Типобезопасное создание элементов
const typedUser = await manager.createElement<GeneratedUser>('User', {
  id: crypto.randomUUID(),
  name: 'Alice',
  email: 'alice@example.com'
});

// TypeScript знает типы полей
const userName: string = typedUser.getField('name');
const userAge: number | undefined = typedUser.getField('age');
```

## 🔧 Интеграция с другими системами

### React интеграция

```typescript
import React, { useState, useEffect } from 'react';
import { useTypedElement } from 'cs-element/react';

interface UserFormProps {
  userId?: string;
}

function UserForm({ userId }: UserFormProps) {
  const [user, setUser] = useTypedElement('User', userId);
  const [errors, setErrors] = useState<Record<string, string>>({});
  
  const handleFieldChange = async (fieldName: string, value: any) => {
    try {
      await user.setField(fieldName, value);
      setErrors(prev => ({ ...prev, [fieldName]: '' }));
    } catch (error) {
      setErrors(prev => ({ ...prev, [fieldName]: error.message }));
    }
  };
  
  const handleSubmit = async () => {
    try {
      await user.validate();
      await user.save();
      console.log('Пользователь сохранен');
    } catch (error) {
      console.error('Ошибка сохранения:', error);
    }
  };
  
  if (!user) return <div>Загрузка...</div>;
  
  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label>Имя:</label>
        <input
          value={user.getField('name') || ''}
          onChange={(e) => handleFieldChange('name', e.target.value)}
        />
        {errors.name && <span className="error">{errors.name}</span>}
      </div>
      
      <div>
        <label>Email:</label>
        <input
          type="email"
          value={user.getField('email') || ''}
          onChange={(e) => handleFieldChange('email', e.target.value)}
        />
        {errors.email && <span className="error">{errors.email}</span>}
      </div>
      
      <div>
        <label>Возраст:</label>
        <input
          type="number"
          value={user.getField('age') || ''}
          onChange={(e) => handleFieldChange('age', parseInt(e.target.value))}
        />
        {errors.age && <span className="error">{errors.age}</span>}
      </div>
      
      <button type="submit" disabled={!user.isValid()}>
        Сохранить
      </button>
    </form>
  );
}
```

### API интеграция

```typescript
// REST API для типизированных элементов
class TypedElementAPI {
  constructor(private manager: TypedElementManager) {}
  
  async createElement(req, res) {
    try {
      const { schemaId, data } = req.body;
      
      const element = await this.manager.createElement(schemaId, data);
      
      res.json({
        success: true,
        element: {
          id: element.id,
          schemaId: element.schemaId,
          data: element.getData(),
          isValid: element.isValid()
        }
      });
    } catch (error) {
      res.status(400).json({
        success: false,
        error: error.message,
        validationErrors: error.validationErrors || []
      });
    }
  }
  
  async updateElement(req, res) {
    try {
      const { id } = req.params;
      const { updates } = req.body;
      
      const element = await this.manager.loadElement(id);
      
      for (const [field, value] of Object.entries(updates)) {
        await element.setField(field, value);
      }
      
      await element.save();
      
      res.json({
        success: true,
        element: {
          id: element.id,
          data: element.getData(),
          isValid: element.isValid()
        }
      });
    } catch (error) {
      res.status(400).json({
        success: false,
        error: error.message
      });
    }
  }
  
  async validateElement(req, res) {
    try {
      const { schemaId, data } = req.body;
      
      const validationResult = await this.manager.validateData(schemaId, data);
      
      res.json({
        success: true,
        isValid: validationResult.isValid,
        errors: validationResult.errors,
        warnings: validationResult.warnings
      });
    } catch (error) {
      res.status(500).json({
        success: false,
        error: error.message
      });
    }
  }
}
```

## 🚨 Устранение неполадок

### Общие проблемы

**Проблема:** Медленная валидация сложных схем
```typescript
// ❌ Неправильно - валидация на каждое изменение
await user.setField('name', 'John');
await user.setField('email', 'john@example.com');
await user.setField('age', 30);

// ✅ Правильно - пакетное обновление
await user.updateFields({
  name: 'John',
  email: 'john@example.com',
  age: 30
});
```

**Проблема:** Циклические зависимости в вычисляемых полях
```typescript
// ❌ Неправильно - циклическая зависимость
const badSchema: Schema = {
  properties: {
    a: { 'x-computed': { dependencies: ['b'], compute: (data) => data.b + 1 } },
    b: { 'x-computed': { dependencies: ['a'], compute: (data) => data.a + 1 } }
  }
};

// ✅ Правильно - разрыв цикла
const goodSchema: Schema = {
  properties: {
    base: { type: 'number' },
    a: { 'x-computed': { dependencies: ['base'], compute: (data) => data.base + 1 } },
    b: { 'x-computed': { dependencies: ['a'], compute: (data) => data.a + 1 } }
  }
};
```

### Диагностика

```typescript
// Диагностика производительности схем
const diagnostics = await manager.diagnoseSchema('User');

console.log('Диагностика схемы:', {
  complexity: diagnostics.complexity,
  validationTime: diagnostics.averageValidationTime,
  computedFieldCount: diagnostics.computedFieldCount,
  recommendations: diagnostics.recommendations
});

// Профилирование валидации
const profilingResult = await manager.profileValidation('User', userData);

console.log('Профилирование валидации:', {
  totalTime: profilingResult.totalTime,
  fieldTimes: profilingResult.fieldTimes,
  bottlenecks: profilingResult.bottlenecks
});
```

Расширенная система типизированных элементов CSElement предоставляет мощные инструменты для создания строго типизированных, валидируемых и расширяемых структур данных с полной интеграцией в TypeScript экосистему. 