UNPKG

userface

Version:

Universal Data-Driven UI Engine with live data, validation, and multi-platform support

255 lines (254 loc) 10.6 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.UnifiedEngine = void 0; const ts = __importStar(require("typescript")); const standalone_1 = require("@babel/standalone"); const parser = __importStar(require("@babel/parser")); const traverse_1 = __importDefault(require("@babel/traverse")); const generator_1 = __importDefault(require("@babel/generator")); /** * Унифицированный движок для обработки компонентов * Объединяет AST анализ, Babel компиляцию, регистрацию */ class UnifiedEngine { constructor() { Object.defineProperty(this, "componentRegistry", { enumerable: true, configurable: true, writable: true, value: new Map() }); Object.defineProperty(this, "styleRegistry", { enumerable: true, configurable: true, writable: true, value: new Map() }); } /** * Основной метод: обрабатывает компонент от кода до готовой схемы */ async processComponent(input) { console.log(`[UnifiedEngine] Processing component: ${input.name}`); // 1. AST Анализ (извлекаем пропсы и метаданные) const schema = await this.analyzeComponent(input); console.log(`[UnifiedEngine] Schema generated:`, schema); // 2. Babel Компиляция (TSX -> JS + обработка импортов) const { compiledCode, cssImports } = await this.compileComponent(input); console.log(`[UnifiedEngine] Compilation complete, CSS imports:`, cssImports); // 3. Генерация дефолтных пропсов const props = this.generateDefaultProps(schema); console.log(`[UnifiedEngine] Default props:`, props); // 4. Создаем финальный объект const processed = { name: input.name, compiledCode, schema, cssImports, props }; // 5. Регистрируем в движке this.componentRegistry.set(input.name, processed); console.log(`[UnifiedEngine] Component registered: ${input.name}`); return processed; } /** * AST анализ компонента */ async analyzeComponent(input) { console.log(`[UnifiedEngine] Starting AST analysis for: ${input.name}`); // Создаем TypeScript программу const sourceFile = ts.createSourceFile(`${input.name}.tsx`, input.code, ts.ScriptTarget.Latest, true, ts.ScriptKind.TSX); const props = []; let componentFound = false; // Обходим AST const visit = (node) => { // Ищем интерфейс пропсов if (ts.isInterfaceDeclaration(node) && node.name.text.includes('Props')) { console.log(`[UnifiedEngine] Found props interface: ${node.name.text}`); node.members.forEach(member => { if (ts.isPropertySignature(member) && member.name && ts.isIdentifier(member.name)) { const propName = member.name.text; const isRequired = !member.questionToken; const typeText = member.type ? sourceFile.text.substring(member.type.pos, member.type.end).trim() : 'any'; // Определяем тип пропа let propType = 'text'; if (typeText.includes('boolean')) propType = 'boolean'; else if (typeText.includes('number')) propType = 'number'; else if (typeText.includes('function') || typeText.includes('=>')) propType = 'function'; props.push({ name: propName, type: propType, required: isRequired, description: `${propName}: ${typeText};` }); console.log(`[UnifiedEngine] Found prop: ${propName} (${propType}, required: ${isRequired})`); } }); } // Ищем компонент if (ts.isFunctionDeclaration(node) || ts.isVariableDeclaration(node)) { const name = node.name?.getText(sourceFile); if (name === input.name) { componentFound = true; console.log(`[UnifiedEngine] Found component declaration: ${name}`); } } ts.forEachChild(node, visit); }; visit(sourceFile); if (!componentFound) { console.warn(`[UnifiedEngine] Component ${input.name} not found in code`); } const schema = { name: input.name, detectedPlatform: 'react', props, events: [], children: true, description: `Auto-generated schema for ${input.name}`, supportsChildren: true }; console.log(`[UnifiedEngine] AST analysis complete for ${input.name}:`, schema); return schema; } /** * Babel компиляция компонента */ async compileComponent(input) { console.log(`[UnifiedEngine] Starting Babel compilation for: ${input.name}`); // Парсим AST для обработки импортов const ast = parser.parse(input.code, { sourceType: 'module', plugins: ['typescript', 'jsx'], }); const cssImports = []; // Обрабатываем импорты (0, traverse_1.default)(ast, { ImportDeclaration(path) { const source = path.node.source.value; if (source.endsWith('.css')) { // Сохраняем CSS импорты и удаляем из кода cssImports.push(source); path.remove(); console.log(`[UnifiedEngine] Found CSS import: ${source}`); } else if (source === 'react' || source === 'react-dom') { // Заменяем на CDN импорты для клиента path.node.source.value = `https://esm.sh/${source}`; console.log(`[UnifiedEngine] Replaced import: ${source} -> https://esm.sh/${source}`); } }, }); // Генерируем обновленный код const { code: transformedCode } = (0, generator_1.default)(ast); // Компилируем через Babel const compiled = (0, standalone_1.transform)(transformedCode, { presets: ['react', 'typescript'], filename: `${input.name}.tsx`, }); if (!compiled.code) { throw new Error(`Babel compilation failed for ${input.name}`); } console.log(`[UnifiedEngine] Babel compilation complete for ${input.name}`); return { compiledCode: compiled.code, cssImports }; } /** * Генерация дефолтных значений пропсов */ generateDefaultProps(schema) { const props = {}; schema.props.forEach(prop => { if (prop.required && ['text', 'boolean', 'number'].includes(prop.type)) { switch (prop.type) { case 'text': props[prop.name] = 'Sample Text'; break; case 'boolean': props[prop.name] = false; break; case 'number': props[prop.name] = 0; break; } } }); return props; } /** * Получение обработанного компонента */ getProcessedComponent(name) { return this.componentRegistry.get(name); } /** * Получение всех зарегистрированных компонентов */ getAllComponents() { return Array.from(this.componentRegistry.keys()); } /** * Регистрация CSS стилей */ registerStyles(name, css) { this.styleRegistry.set(name, css); console.log(`[UnifiedEngine] Styles registered for: ${name}`); } /** * Получение CSS стилей */ getStyles(name) { return this.styleRegistry.get(name); } /** * Очистка реестра */ clear() { this.componentRegistry.clear(); this.styleRegistry.clear(); console.log(`[UnifiedEngine] Registry cleared`); } } exports.UnifiedEngine = UnifiedEngine;