userface
Version:
Universal Data-Driven UI Engine with live data, validation, and multi-platform support
249 lines (248 loc) • 11 kB
JavaScript
"use strict";
// Универсальная генерация пропсов для компонентов
// Анализирует схему компонента и генерирует подходящие пропсы без хардкода
Object.defineProperty(exports, "__esModule", { value: true });
exports.PropGenerator = void 0;
exports.filterDOMProps = filterDOMProps;
/**
* Фильтрует пропсы, убирая те, которые не должны передаваться на DOM элементы
*/
function filterDOMProps(props) {
const filtered = {};
// Список пропсов, которые НЕ должны передаваться на DOM
const invalidDOMProps = new Set([
'isopen', 'showLabel', 'isOpen', 'isVisible', 'isActive',
'isSelected', 'isDisabled', 'isLoading', 'isError', 'isSuccess',
'hasError', 'hasWarning', 'hasInfo', 'hasSuccess',
'canEdit', 'canDelete', 'canView', 'canCreate',
'shouldShow', 'shouldHide', 'shouldRender', 'shouldUpdate',
'onToggle', 'onShow', 'onHide', 'onOpen', 'onClose',
'items', 'options', 'data', 'tabs', 'sections', 'fields',
'children', 'render', 'component', 'as', 'forwardedRef',
'defaultActiveTab', 'activeTab', 'currentTab',
'variant', 'size', 'theme', 'color', 'backgroundColor'
]);
for (const [key, value] of Object.entries(props)) {
const keyLower = key.toLowerCase();
// Всегда передаем стандартные React пропсы
if (key === 'children' || key === 'ref' || key === 'key') {
filtered[key] = value;
continue;
}
// Всегда передаем data-* и aria-* атрибуты
if (key.startsWith('data-') || key.startsWith('aria-')) {
filtered[key] = value;
continue;
}
// Пропускаем невалидные DOM пропсы
if (invalidDOMProps.has(keyLower)) {
continue;
}
// Передаем все остальные пропсы (стандартные HTML атрибуты)
filtered[key] = value;
}
return filtered;
}
/**
* Универсальная генерация пропсов на основе анализа компонента
*/
class PropGenerator {
/**
* Генерирует пропсы для компонента на основе его схемы
*/
static generateProps(schema, componentName) {
const props = {
id: `${componentName.toLowerCase()}-demo`
};
if (!schema.props || !Array.isArray(schema.props)) {
return props;
}
// Обрабатываем каждый проп из схемы
schema.props.forEach((prop) => {
const propName = prop.name;
const propType = prop.type;
const isRequired = prop.required;
// Генерируем значение на основе типа и контекста пропа
const value = this.generateValueForType(propType, propName, isRequired);
if (value !== undefined) {
props[propName] = value;
}
});
return props;
}
/**
* Универсальная генерация значения для конкретного типа пропа
*/
static generateValueForType(type, name, required) {
const typeLower = type.toLowerCase();
const nameLower = name.toLowerCase();
// === ОБРАБОТКА КОНТРОЛИРУЕМЫХ КОМПОНЕНТОВ ===
// Для value/checked без onChange - не передаем, пусть компонент использует defaultValue/defaultChecked
if ((nameLower.includes('value') || nameLower.includes('checked')) &&
!nameLower.includes('onchange') && !nameLower.includes('onclick')) {
return undefined;
}
// === ОБРАБОТКА ФУНКЦИЙ ===
if (typeLower.includes('function') ||
nameLower.includes('on') ||
nameLower.includes('handle') ||
nameLower.includes('callback')) {
return () => console.log(`Function ${name} called`);
}
// === УНИВЕРСАЛЬНАЯ ОБРАБОТКА МАССИВОВ ===
if (typeLower.includes('array') || typeLower.includes('[]')) {
return this.generateArrayValue(nameLower);
}
// === ОБЩИЕ ТИПЫ ===
// Строки
if (typeLower.includes('string') || typeLower.includes('text')) {
return this.generateStringValue(nameLower);
}
// Числа
if (typeLower.includes('number') || typeLower.includes('int')) {
return this.generateNumberValue(nameLower);
}
// Булевы значения
if (typeLower.includes('boolean') || typeLower.includes('bool')) {
return false;
}
// Объекты
if (typeLower.includes('object') || typeLower.includes('{}')) {
return {};
}
// Дефолтное значение для неизвестных типов
return required ? 'Default value' : undefined;
}
/**
* Универсальная генерация строковых значений
*/
static generateStringValue(nameLower) {
// Специальные случаи для строк
if (nameLower.includes('placeholder'))
return 'Enter text...';
if (nameLower.includes('label'))
return 'Label';
if (nameLower.includes('title'))
return 'Title';
if (nameLower.includes('content'))
return 'Content';
if (nameLower.includes('text'))
return 'Sample text';
if (nameLower.includes('src') || nameLower.includes('source'))
return 'https://via.placeholder.com/300x200';
if (nameLower.includes('alt') || nameLower.includes('alttext'))
return 'Sample image';
if (nameLower.includes('href') || nameLower.includes('url'))
return '#';
if (nameLower.includes('name'))
return 'sample-name';
if (nameLower.includes('id'))
return 'sample-id';
if (nameLower.includes('class'))
return 'sample-class';
// Дефолтное значение
return 'Sample text';
}
/**
* Универсальная генерация числовых значений
*/
static generateNumberValue(nameLower) {
// Специальные случаи для чисел
if (nameLower.includes('min'))
return 0;
if (nameLower.includes('max'))
return 100;
if (nameLower.includes('value'))
return 50;
if (nameLower.includes('progress'))
return 65;
if (nameLower.includes('width'))
return 300;
if (nameLower.includes('height'))
return 200;
if (nameLower.includes('size'))
return 16;
if (nameLower.includes('count'))
return 5;
if (nameLower.includes('limit'))
return 10;
if (nameLower.includes('step'))
return 1;
if (nameLower.includes('delay'))
return 1000;
if (nameLower.includes('duration'))
return 300;
// Дефолтное значение
return 42;
}
/**
* Универсальная генерация массивов
*/
static generateArrayValue(nameLower) {
// Определяем тип массива по имени пропа
if (nameLower.includes('options') || nameLower.includes('choices')) {
return [
{ value: 'option1', label: 'Option 1' },
{ value: 'option2', label: 'Option 2' },
{ value: 'option3', label: 'Option 3' }
];
}
if (nameLower.includes('items') || nameLower.includes('list')) {
return [
{ id: '1', text: 'Item 1', title: 'First Item' },
{ id: '2', text: 'Item 2', title: 'Second Item' },
{ id: '3', text: 'Item 3', title: 'Third Item' }
];
}
if (nameLower.includes('data') || nameLower.includes('rows')) {
return [
{ id: 1, name: 'Row 1', value: 'Value 1', status: 'Active' },
{ id: 2, name: 'Row 2', value: 'Value 2', status: 'Inactive' },
{ id: 3, name: 'Row 3', value: 'Value 3', status: 'Active' }
];
}
if (nameLower.includes('tabs') || nameLower.includes('sections')) {
return [
{ id: 'tab1', label: 'Tab 1', content: 'Content for tab 1' },
{ id: 'tab2', label: 'Tab 2', content: 'Content for tab 2' },
{ id: 'tab3', label: 'Tab 3', content: 'Content for tab 3' }
];
}
if (nameLower.includes('fields') || nameLower.includes('inputs')) {
return [
{ id: 'field1', label: 'Field 1', type: 'text', placeholder: 'Enter field 1' },
{ id: 'field2', label: 'Field 2', type: 'select', options: ['Option 1', 'Option 2'] }
];
}
if (nameLower.includes('posts') || nameLower.includes('articles')) {
return [
{ id: '1', author: 'John Doe', title: 'First Post', content: 'This is the content of the first post.', date: '2024-01-15 10:30' },
{ id: '2', author: 'Jane Smith', title: 'Second Post', content: 'Another interesting post content.', date: '2024-01-15 11:45' }
];
}
if (nameLower.includes('products') || nameLower.includes('goods')) {
return [
{ id: '1', name: 'Product 1', price: 29.99, quantity: 2, image: 'product1.jpg' },
{ id: '2', name: 'Product 2', price: 19.99, quantity: 1, image: 'product2.jpg' }
];
}
// Универсальный массив для неизвестных типов
return [
{ id: '1', name: 'Item 1', value: 'Value 1' },
{ id: '2', name: 'Item 2', value: 'Value 2' },
{ id: '3', name: 'Item 3', value: 'Value 3' }
];
}
/**
* Генерирует дефолтные пропсы если анализ не удался
*/
static generateDefaultProps(componentName) {
return {
id: `${componentName.toLowerCase()}-demo`,
// Базовые пропсы для большинства компонентов
className: 'demo-component',
style: { margin: '8px' }
};
}
}
exports.PropGenerator = PropGenerator;