userface
Version:
Universal Data-Driven UI Engine with live data, validation, and multi-platform support
202 lines (201 loc) • 7.9 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.SpecGenerator = void 0;
class SpecGenerator {
/**
* Генерирует JSON-спеку компонента на основе AST анализа
*/
generateSpecFromAnalysis(analysis) {
const variants = [];
// Генерируем варианты для каждого типа пропса
const variantProps = this.generateVariantsForProps(analysis.props);
// Создаем комбинации вариантов
const combinations = this.generateCombinations(variantProps);
// Преобразуем в варианты компонента
combinations.forEach((combo, index) => {
variants.push({
name: `variant-${index + 1}`,
description: this.generateVariantDescription(combo),
props: combo
});
});
// Добавляем дефолтный вариант
const defaultProps = this.generateDefaultProps(analysis.props);
variants.unshift({
name: 'default',
description: 'Default variant with basic props',
props: defaultProps
});
return {
name: analysis.name,
description: analysis.description || `Component ${analysis.name}`,
variants,
defaultVariant: 'default'
};
}
/**
* Генерирует варианты для каждого пропа на основе его типа
*/
generateVariantsForProps(props) {
const variants = {};
props.forEach(prop => {
if (prop.required) {
// Для обязательных пропсов создаем базовые значения
variants[prop.name] = [this.generateValueForType(prop.type, prop.description)];
}
else {
// Для опциональных создаем несколько вариантов
variants[prop.name] = this.generateValuesForType(prop.type, prop.description);
}
});
return variants;
}
/**
* Генерирует значение для конкретного типа
*/
generateValueForType(type, description) {
// Сначала проверяем union types в самом типе
const unionValues = this.extractUnionValues(type);
if (unionValues.length > 0) {
return unionValues[0]; // Возвращаем первое значение из union
}
// Затем проверяем union types в описании
const descUnionValue = this.extractTextValue(description);
if (descUnionValue) {
return descUnionValue;
}
// Если union types не найдены, используем стандартные значения
switch (type) {
case 'text':
case 'string':
return 'Sample Text';
case 'boolean':
return true;
case 'number':
return 42;
case 'array':
return [];
case 'function':
return () => { };
default:
return null;
}
}
/**
* Генерирует несколько значений для типа
*/
generateValuesForType(type, description) {
// Сначала проверяем union types в самом типе
const unionValues = this.extractUnionValues(type);
if (unionValues.length > 0) {
return unionValues;
}
// Затем проверяем union types в описании
const descUnionValues = this.extractTextValues(description);
if (descUnionValues.length > 0) {
return descUnionValues;
}
// Если union types не найдены, используем стандартные значения
switch (type) {
case 'text':
case 'string':
return ['Sample Text', 'Another Text'];
case 'boolean':
return [true, false];
case 'number':
return [0, 42, 100];
case 'array':
return [[], [1, 2, 3]];
case 'function':
return [() => { }, () => console.log('clicked')];
default:
return [null];
}
}
/**
* Извлекает возможные значения из union types в типе (например: 'primary' | 'secondary')
*/
extractUnionValues(type) {
// Ищем union types в формате 'value1' | 'value2' | 'value3'
const unionMatch = type.match(/'([^']+)'(?:\s*\|\s*'([^']+)')*/g);
if (unionMatch) {
return unionMatch.map(match => match.replace(/'/g, ''));
}
// Ищем union types в формате "value1" | "value2" | "value3"
const unionMatchDouble = type.match(/"([^"]+)"(?:\s*\|\s*"([^"]+)")*/g);
if (unionMatchDouble) {
return unionMatchDouble.map(match => match.replace(/"/g, ''));
}
// Ищем union types без кавычек (например: primary | secondary)
const unionMatchNoQuotes = type.match(/(\w+)(?:\s*\|\s*(\w+))*/g);
if (unionMatchNoQuotes && unionMatchNoQuotes.length > 1) {
return unionMatchNoQuotes;
}
return [];
}
/**
* Извлекает возможные значения из union types в описании (например: 'primary' | 'secondary')
*/
extractTextValues(description) {
const unionMatch = description.match(/'([^']+)'(?:\s*\|\s*'([^']+)')*/g);
if (unionMatch) {
return unionMatch.map(match => match.replace(/'/g, ''));
}
return [];
}
/**
* Извлекает одно значение из union type
*/
extractTextValue(description) {
const values = this.extractTextValues(description);
return values.length > 0 ? values[0] : null;
}
/**
* Генерирует все возможные комбинации вариантов пропсов
*/
generateCombinations(variantProps) {
const keys = Object.keys(variantProps);
if (keys.length === 0)
return [{}];
const combinations = [];
const generateCombos = (index, current) => {
if (index === keys.length) {
combinations.push({ ...current });
return;
}
const key = keys[index];
const values = variantProps[key];
values.forEach(value => {
current[key] = value;
generateCombos(index + 1, current);
});
};
generateCombos(0, {});
return combinations;
}
/**
* Генерирует дефолтные пропсы
*/
generateDefaultProps(props) {
const defaultProps = {};
props.forEach(prop => {
if (prop.required) {
defaultProps[prop.name] = this.generateValueForType(prop.type, prop.description);
}
});
return defaultProps;
}
/**
* Генерирует описание варианта
*/
generateVariantDescription(props) {
const descriptions = [];
Object.entries(props).forEach(([key, value]) => {
if (value !== null && value !== undefined) {
descriptions.push(`${key}: ${String(value)}`);
}
});
return descriptions.length > 0 ? descriptions.join(', ') : 'Custom variant';
}
}
exports.SpecGenerator = SpecGenerator;