UNPKG

@meta-aiml/parser

Version:

AIML Parser SDK v2.0.1 - Production-ready schema validation for Meta-AIML.org entity schemas. Supports all 31 entity types with enhanced error handling, universal browser compatibility, and complete API implementation. Zero exceptions, works everywhere.

1,001 lines (887 loc) 38.5 kB
/** * AIML Parser SDK v2.0.1 - Updated to match UI validator logic exactly * * Complete schema validation for Meta-AIML.org entity schemas. * Supports all 31 entity types across 6 categories with comprehensive validation. * NOW WITH SAME LOGIC AS UI VALIDATOR (META-AIML Intelligent Scoring Engine) * * @version 2.0.1 * @author META-AIML.ORG - IURII IURIEV * @repository https://github.com/meta-aiml-org/SDK * @npm https://www.npmjs.com/package/@meta-aiml/parser * @date 2025-07-02 */ /** * @typedef {Object} AIMLValidationError * @property {string} field - Field with error * @property {string} message - Error message * @property {'error'|'warning'|'info'} severity - Error severity * @property {'structure'|'schema'|'semantic'|'performance'|'best_practice'} category - Error category * @property {string} [suggestion] - Fix suggestion * @property {string} [documentation] - Documentation link * @property {number} [line] - Line number * @property {number} [column] - Column number */ /** * @typedef {Object} AIMLEntityInfo * @property {string} entityType - Entity type * @property {string} entityCategory - Entity category * @property {string} [subcategory] - Subcategory * @property {string} baseSchema - Base schema * @property {string[]} modules - Active modules * @property {boolean} hasEntityCapabilities - Has entity capabilities (v2.0.1) * @property {boolean} hasSiteCapabilities - Has site capabilities (v2.0.1) */ /** * @typedef {Object} AIMLValidationResult * @property {boolean} isValid - Is schema valid * @property {AIMLValidationError[]} errors - Critical errors * @property {AIMLValidationError[]} warnings - Warnings * @property {AIMLValidationError[]} suggestions - Improvement suggestions * @property {AIMLEntityInfo} [entityInfo] - Entity information * @property {number} score - Quality score (0-100) * @property {number} completeness - Completeness score (0-100) * @property {Object} performance - Performance metrics * @property {number} performance.schemaSize - Schema size in bytes * @property {'low'|'medium'|'high'} performance.complexity - Complexity level * @property {number} performance.moduleCount - Number of modules */ /** * @typedef {Object} AIMLSchema * @property {string} [@context] - JSON-LD context * @property {string} [@id] - Unique identifier * @property {string} [@type] - Entity type * @property {string} [schemaVersion] - AIML schema version * @property {string} [entityType] - AIML entity type * @property {string} [entityCategory] - Top-level category * @property {string} [subcategory] - Subcategory * @property {Object} [name] - Multilingual name object (required in v2.0.1) * @property {Object} [description] - Multilingual description object (required in v2.0.1) * @property {string} [url] - URL * @property {string} [shortDescription] - Short description * @property {Object} [properties] - Entity properties * @property {Object} [modules] - Enabled modules * @property {Object} [entityCapabilities] - Entity capabilities (NEW in v2.0.1) * @property {Object} [siteCapabilities] - Site capabilities (NEW in v2.0.1) */ // AIML v2.0.1 specifications - Updated to match UI validator exactly const AIML_CONTEXT = "https://schemas.meta-aiml.org/v2.0.1/context.jsonld"; const AIML_VERSION = "2.0.1"; const BASE_CATEGORIES = [ "organization", "product_offering", "service", "creative_work", "community", "financial_product" ]; const ENTITY_TYPES = { organization: [ "clinic", "education_platform", "fitness_platform", "hotel", "restaurant", "store" ], product_offering: [ "ecommerce_store", "marketplace", "product", "software_product" ], service: [ "business_services", "generative_ai_platform", "real_estate_platform", "ridesharing_service", "task_management_app", "telemedicine_platform", "virtual_event_platform", "web_app", "website_services" ], creative_work: [ "blog", "event", "file_hosting", "gaming_platform", "news", "personal_website", "photo_hosting", "streaming_platform", "video_hosting" ], community: ["dating_platform", "social_network"], financial_product: ["online_banking"] }; const SUBCATEGORIES = { ecommerce_platform: ["ecommerce_store", "marketplace", "store"], hospitality: ["hotel", "restaurant"], healthcare_services: ["clinic", "fitness_platform", "telemedicine_platform"], education_services: ["education_platform"], ai_platform: ["generative_ai_platform"], professional_services: ["business_services"], ridesharing_services: ["ridesharing_service"], website_services: ["website_services"], property_services: ["real_estate_platform"], physical_product: ["product"], digital_product: ["file_hosting", "personal_website", "software_product", "task_management_app", "web_app"], media_entertainment: ["blog", "gaming_platform", "news", "photo_hosting", "streaming_platform", "video_hosting"], social_platform: ["dating_platform", "social_network"], event_platform: ["event", "virtual_event_platform"], financial_services: ["online_banking"] }; // Enhanced subcategory validation rules - SAME AS UI VALIDATOR const SUBCATEGORY_VALIDATION_RULES = { professional_services: { allowedCategories: ["service"], description: "Professional and business services" }, event_platform: { allowedCategories: ["creative_work", "service"], description: "Event organization and management platforms" }, physical_product: { allowedCategories: ["product_offering"], description: "Physical goods and products" }, website_services: { allowedCategories: ["service"], description: "Website development and maintenance services" }, gaming_platform: { allowedCategories: ["creative_work"], description: "Gaming and interactive entertainment platforms" } }; const AVAILABLE_MODULES = [ "auth", "compliance", "location", "logistics", "multilingual", "notification", "payments", "recommendations", "search", "security", "streaming", "subscription", "user-management", "warranty" ]; // Required modules by entity type (from required_fields_v2.0.1.md) - SAME AS UI VALIDATOR const REQUIRED_MODULES = { "clinic": ["auth", "security", "compliance"], "education_platform": ["auth", "user-management"], "hotel": ["location", "payments"], "restaurant": ["location"], "ecommerce_store": ["auth", "payments"], "marketplace": ["auth", "payments", "user-management"], "generative_ai_platform": ["auth", "security"], "ridesharing_service": ["auth", "location"], "social_network": ["auth", "user-management"], "online_banking": ["auth", "security", "compliance"], "telemedicine_platform": ["auth", "security", "compliance", "streaming"], "dating_platform": ["auth", "user-management"] }; /** * AIML Parser SDK v2.0.1 - Official Release * * NOW WITH EXACT SAME LOGIC AS UI VALIDATOR * ✅ Same validation rules * ✅ Same scoring system (META-AIML Intelligent Scoring Engine) * ✅ Same completeness calculation * * @class AIMLParser */ class AIMLParser { /** * Initialize AIML Parser * * @param {Object} [options] - Parser configuration * @param {boolean} [options.debug=false] - Enable debug mode * @param {boolean} [options.strict=false] - Enable strict validation * @param {string} [options.version='2.0.1'] - Target AIML version */ constructor(options = {}) { this.config = { debug: options.debug || false, strict: options.strict || false, version: options.version || AIML_VERSION }; // State for validation this.errors = []; this.warnings = []; this.suggestions = []; } /** * Validate AIML schema - SAME LOGIC AS UI VALIDATOR * * @param {string|Object} data - Schema to validate (JSON string or object) * @returns {AIMLValidationResult} Validation result */ validate(data) { // Reset state this.errors = []; this.warnings = []; this.suggestions = []; // Handle null/undefined gracefully - FIXED ERROR HANDLING if (data === null) { this._addError('input', 'Input data is null', 'structure', 'Provide a valid AIML schema object or JSON string'); return this._buildResult(false, null); } if (data === undefined) { this._addError('input', 'Input data is undefined', 'structure', 'Provide a valid AIML schema object or JSON string'); return this._buildResult(false, null); } // Handle empty input gracefully if (data === '' || (typeof data === 'string' && data.trim() === '')) { this._addError('input', 'Input data is empty', 'structure', 'Provide a valid AIML schema object or JSON string'); return this._buildResult(false, null); } let schema; try { schema = typeof data === 'string' ? JSON.parse(data) : data; } catch (error) { this._addError('JSON', 'Invalid JSON syntax', 'structure', 'Please check for missing commas, brackets, or quotes'); return this._buildResult(false, null); } // Core validation pipeline - SAME AS UI VALIDATOR this._validateRequiredFields(schema); this._validateContext(schema); this._validateVersioning(schema); this._validateEntityStructure(schema); this._validateNames(schema); this._validateModules(schema); this._validateEntityCapabilities(schema); this._validateSiteCapabilities(schema); this._validateBestPractices(schema); const entityInfo = this._extractEntityInfo(schema); const isValid = this.errors.length === 0; return this._buildResult(isValid, entityInfo, schema); } /** * Quick validation without detailed analysis * @param {string|Object} data - Schema to validate * @returns {boolean} True if valid */ isValid(data) { return this.validate(data).isValid; } /** * Get detailed entity information * @param {string|Object} data - Schema to analyze * @returns {AIMLEntityInfo|null} Entity information */ getEntityInfo(data) { const result = this.validate(data); return result.entityInfo; } /** * Validate required fields - SAME AS UI VALIDATOR * @private */ _validateRequiredFields(schema) { // Critical required fields (ERRORS if missing) from required_fields_v2.0.1.md const criticalRequired = ['@context', '@id', '@type', 'schemaVersion', 'entityType', 'entityCategory', 'name', 'description']; criticalRequired.forEach(field => { if (!schema[field]) { this._addError(field, `Critical required field '${field}' is missing`, 'structure', `Add the ${field} field to your schema (required for v2.0.1 compliance)`); } }); // Strongly recommended fields (WARNINGS if missing) const stronglyRecommended = ['url', 'shortDescription']; stronglyRecommended.forEach(field => { if (!schema[field]) { this._addWarning(field, `Strongly recommended field '${field}' is missing`, 'best_practice', `Add ${field} for better schema completeness and usability`); } }); // NEW v2.0.1 required fields const newRequiredFields = ['entityCapabilities', 'siteCapabilities']; newRequiredFields.forEach(field => { if (!schema[field]) { this._addWarning(field, `NEW v2.0.1 field '${field}' is missing`, 'semantic', `Add ${field} - new requirement in v2.0.1 for comprehensive entity description`); } }); // Category-specific required fields if (schema.entityCategory) { switch (schema.entityCategory) { case 'organization': if (!schema.foundingDate) { this._addWarning('foundingDate', 'foundingDate is required for organization entities', 'schema', 'Add foundingDate in ISO 8601 format (YYYY-MM-DD)'); } break; case 'product_offering': if (!schema.properties) { this._addWarning('properties', 'properties object is required for product_offering entities', 'schema', 'Add properties object with product/offering characteristics'); } break; case 'service': if (!schema.serviceType) { this._addSuggestion('serviceType', 'serviceType is recommended for service entities', 'schema', 'Add serviceType to specify the type of service provided'); } break; case 'creative_work': if (!schema.properties) { this._addSuggestion('properties', 'properties object is recommended for creative_work entities', 'schema', 'Add properties object with content characteristics'); } break; } } } /** * Validate @context - SAME AS UI VALIDATOR * @private */ _validateContext(schema) { if (!schema['@context']) { this._addError('@context', '@context is required for JSON-LD compliance', 'structure', `Add "@context": "${AIML_CONTEXT}"`); } else if (schema['@context'] !== AIML_CONTEXT) { this._addError('@context', 'Invalid @context value - must be exact', 'structure', `Use exactly "${AIML_CONTEXT}" for AIML v2.0.1 schemas`); } } /** * Validate versioning - SAME AS UI VALIDATOR * @private */ _validateVersioning(schema) { if (!schema.schemaVersion) { this._addError('schemaVersion', 'schemaVersion is required for v2.0.1 compliance', 'structure', `Add "schemaVersion": "${AIML_VERSION}"`); } else if (schema.schemaVersion !== AIML_VERSION) { this._addError('schemaVersion', `Invalid schema version: ${schema.schemaVersion}`, 'schema', `Must be exactly "${AIML_VERSION}" for current META-AIML compliance`); } } /** * Validate entity structure - SAME AS UI VALIDATOR * @private */ _validateEntityStructure(schema) { // Validate entity category if (schema.entityCategory && !BASE_CATEGORIES.includes(schema.entityCategory)) { this._addError('entityCategory', `Invalid entity category: ${schema.entityCategory}`, 'schema', `Use one of: ${BASE_CATEGORIES.join(', ')}`); } // Validate entity type against category if (schema.entityType && schema.entityCategory) { const validTypes = ENTITY_TYPES[schema.entityCategory] || []; if (validTypes.length > 0 && !validTypes.includes(schema.entityType)) { this._addError('entityType', `Entity type '${schema.entityType}' is not valid for category '${schema.entityCategory}'`, 'schema', `Valid types for ${schema.entityCategory}: ${validTypes.join(', ')}`); } } // Validate subcategory if (schema.subcategory) { const validSubcategories = Object.keys(SUBCATEGORIES); if (!validSubcategories.includes(schema.subcategory)) { this._addWarning('subcategory', `Subcategory '${schema.subcategory}' might not be standard`, 'schema', `Common subcategories: ${validSubcategories.join(', ')}`); } // Validate subcategory against entity category using additional rules if (schema.entityCategory && SUBCATEGORY_VALIDATION_RULES[schema.subcategory]) { const rule = SUBCATEGORY_VALIDATION_RULES[schema.subcategory]; if (!rule.allowedCategories.includes(schema.entityCategory)) { this._addError('subcategory', `Subcategory '${schema.subcategory}' is not valid for category '${schema.entityCategory}'`, 'schema', `Valid categories for ${schema.subcategory}: ${rule.allowedCategories.join(', ')}`); } } // Validate entity type against subcategory if (schema.entityType && SUBCATEGORIES[schema.subcategory]) { const validTypesForSubcategory = SUBCATEGORIES[schema.subcategory]; if (!validTypesForSubcategory.includes(schema.entityType)) { this._addError('entityType', `Entity type '${schema.entityType}' is not valid for subcategory '${schema.subcategory}'`, 'schema', `Valid types for ${schema.subcategory}: ${validTypesForSubcategory.join(', ')}`); } } } } /** * Validate names - SAME AS UI VALIDATOR * @private */ _validateNames(schema) { // Validate name structure - must be multilingual object in v2.0.1 if (schema.name) { if (typeof schema.name === 'string') { this._addError('name', 'name must be a multilingual object in v2.0.1', 'structure', 'Convert to object format: {"en": "Your Name", "es": "Tu Nombre"}'); } else if (typeof schema.name === 'object') { if (!schema.name.en) { this._addError('name', 'English name (en) is required in multilingual names', 'structure', 'Add "en" field - English is required for international compatibility'); } Object.keys(schema.name).forEach(lang => { if (!/^[a-z]{2}(-[A-Z]{2})?$/.test(lang)) { this._addWarning('name', `Language code '${lang}' might not be valid ISO 639-1 format`, 'best_practice', 'Use ISO 639-1 language codes (e.g., "en", "es", "fr", "en-US")'); } // Check for empty values if (!schema.name[lang] || schema.name[lang].trim() === '') { this._addWarning('name', `Empty name value for language '${lang}'`, 'structure', 'Provide meaningful names for all declared languages'); } }); } } // Validate description structure - must be multilingual object in v2.0.1 if (schema.description) { if (typeof schema.description === 'string') { this._addError('description', 'description must be a multilingual object in v2.0.1', 'structure', 'Convert to object format: {"en": "Your Description"}'); } else if (typeof schema.description === 'object') { if (!schema.description.en) { this._addError('description', 'English description (en) is required', 'structure', 'Add "en" field - English description is mandatory'); } // Check description length (minimum 50 characters for English) if (schema.description.en && schema.description.en.length < 50) { this._addWarning('description', 'English description should be at least 50 characters', 'best_practice', 'Provide detailed description for better understanding and SEO'); } Object.keys(schema.description).forEach(lang => { if (!schema.description[lang] || schema.description[lang].trim() === '') { this._addWarning('description', `Empty description value for language '${lang}'`, 'structure', 'Provide meaningful descriptions for all declared languages'); } }); } } } /** * Validate modules - SAME AS UI VALIDATOR * @private */ _validateModules(schema) { // Check for required modules based on entity type if (schema.entityType && REQUIRED_MODULES[schema.entityType]) { const requiredModules = REQUIRED_MODULES[schema.entityType]; const presentModules = schema.modules ? Object.keys(schema.modules) : []; requiredModules.forEach(requiredModule => { if (!presentModules.includes(requiredModule)) { this._addError('modules', `Required module '${requiredModule}' is missing for ${schema.entityType}`, 'schema', `${schema.entityType} entities must include: ${requiredModules.join(', ')}`); } }); } if (schema.modules) { Object.keys(schema.modules).forEach(moduleKey => { if (!AVAILABLE_MODULES.includes(moduleKey)) { this._addWarning('modules', `Module '${moduleKey}' is not a standard AIML module`, 'schema', `Standard modules: ${AVAILABLE_MODULES.join(', ')}`); } const module = schema.modules[moduleKey]; if (module && typeof module === 'object') { if (!module.version) { this._addWarning(`modules.${moduleKey}`, 'Module should include version field', 'best_practice', 'Add version "2.0.1" for compatibility tracking'); } if (module.enabled === undefined) { this._addSuggestion(`modules.${moduleKey}`, 'Consider adding enabled field to module', 'best_practice', 'Add "enabled": true/false for better module management'); } // Version validation for v2.0.1 if (module.version && module.version !== "2.0.1") { this._addWarning(`modules.${moduleKey}`, `Module version ${module.version} might not be current`, 'schema', 'Consider using version "2.0.1" for latest features'); } } }); } // Check for required modules (always check, even if no modules field) if (schema.entityType && REQUIRED_MODULES[schema.entityType]) { const requiredModules = REQUIRED_MODULES[schema.entityType]; const currentModules = schema.modules ? Object.keys(schema.modules) : []; const missingModules = requiredModules.filter(mod => !currentModules.includes(mod)); for (const missingModule of missingModules) { this._addWarning('modules', `Required module '${missingModule}' is missing for entity type '${schema.entityType}'`, 'structure', `Add the '${missingModule}' module for ${schema.entityType} entities`); } } } /** * Validate entity capabilities - SAME AS UI VALIDATOR * @private */ _validateEntityCapabilities(schema) { if (schema.entityCapabilities) { const capabilities = schema.entityCapabilities; // Check for required functionalFeatures (NEW in v2.0.1) if (!capabilities.functionalFeatures) { this._addWarning('entityCapabilities', 'Missing functionalFeatures - these define objective business capabilities', 'semantic', 'Add functionalFeatures object with boolean values for entity capabilities (NEW in v2.0.1)'); } else { // Validate that functionalFeatures are boolean values - critical for objective validation Object.entries(capabilities.functionalFeatures).forEach(([key, value]) => { if (typeof value !== 'boolean') { this._addError('entityCapabilities', `functionalFeatures.${key} should be boolean, got ${typeof value}`, 'semantic', 'Use true/false values for objective, verifiable business features'); } }); // Check for meaningful functional features const featureCount = Object.keys(capabilities.functionalFeatures).length; if (featureCount < 3) { this._addSuggestion('entityCapabilities', 'Consider adding more functionalFeatures for comprehensive business description', 'semantic', 'Add more objective capabilities like acceptsReservations, hasDelivery, acceptsCreditCards, etc.'); } } // Check for required contentTypes array if (!capabilities.contentTypes || !Array.isArray(capabilities.contentTypes)) { this._addWarning('entityCapabilities', 'Missing contentTypes array - define what content types are available', 'semantic', 'Add contentTypes array (e.g., ["menu", "photos", "reviews", "support"])'); } else if (capabilities.contentTypes.length === 0) { this._addWarning('entityCapabilities', 'contentTypes array is empty - add available content types', 'semantic'); } // Check for businessModel (recommended) if (!capabilities.businessModel) { this._addSuggestion('entityCapabilities', 'Consider adding businessModel for better business categorization', 'semantic', 'Add businessModel (e.g., "restaurant", "marketplace", "subscription")'); } // Check for paymentMethods if applicable if (capabilities.functionalFeatures?.supportsOnlinePayments === true) { if (!capabilities.paymentMethods || !Array.isArray(capabilities.paymentMethods)) { this._addSuggestion('entityCapabilities', 'Since online payments are supported, add paymentMethods array', 'semantic', 'Add paymentMethods array (e.g., ["credit_card", "paypal", "digital_wallet"])'); } } } else { this._addWarning('entityCapabilities', 'Missing entityCapabilities - required in v2.0.1 for objective business features', 'semantic', 'Add entityCapabilities with functionalFeatures, contentTypes, and businessModel (NEW in v2.0.1)'); } } /** * Validate site capabilities - SAME AS UI VALIDATOR * @private */ _validateSiteCapabilities(schema) { if (schema.siteCapabilities) { const capabilities = schema.siteCapabilities; // Check for required availableActions array (NEW in v2.0.1) if (!capabilities.availableActions || !Array.isArray(capabilities.availableActions)) { this._addWarning('siteCapabilities', 'Missing availableActions array - define what users can do on the site', 'semantic', 'Add availableActions array (e.g., ["view_menu", "make_reservation", "order_delivery"]) - NEW in v2.0.1'); } else if (capabilities.availableActions.length === 0) { this._addWarning('siteCapabilities', 'availableActions array is empty - add user interaction possibilities', 'semantic'); } // Check for interactionMethods - how users can interact with business if (!capabilities.interactionMethods || !Array.isArray(capabilities.interactionMethods)) { this._addWarning('siteCapabilities', 'Missing interactionMethods - define how users interact with business', 'semantic', 'Add interactionMethods array (e.g., ["online_form", "phone_call", "email"])'); } // Check for contentAccess levels if (!capabilities.contentAccess || !Array.isArray(capabilities.contentAccess)) { this._addSuggestion('siteCapabilities', 'Add contentAccess array for content accessibility levels', 'semantic', 'Add contentAccess (e.g., ["public", "members_only"])'); } // Check for supportedDevices - important for accessibility if (!capabilities.supportedDevices || !Array.isArray(capabilities.supportedDevices)) { this._addWarning('siteCapabilities', 'Missing supportedDevices - important for accessibility information', 'semantic', 'Add supportedDevices array (e.g., ["desktop", "mobile", "tablet"])'); } // Check for languages array if (!capabilities.languages || !Array.isArray(capabilities.languages)) { this._addWarning('siteCapabilities', 'Missing languages array - define interface languages', 'semantic', 'Add languages array for internationalization (e.g., ["en", "es"])'); } // Check for realTimeFeatures if applicable if (!capabilities.realTimeFeatures) { this._addSuggestion('siteCapabilities', 'Consider adding realTimeFeatures if site has real-time functionality', 'semantic', 'Add realTimeFeatures array if applicable (e.g., ["real_time_availability", "instant_booking"])'); } } else { this._addWarning('siteCapabilities', 'Missing siteCapabilities - required in v2.0.1 for website interaction features', 'semantic', 'Add siteCapabilities with availableActions, interactionMethods, and supportedDevices (NEW in v2.0.1)'); } } /** * Validate best practices - SAME AS UI VALIDATOR * @private */ _validateBestPractices(schema) { // URL validation if (schema.url && !/^https?:\/\/.+/.test(schema.url)) { this._addWarning('url', 'URL should start with http:// or https://', 'best_practice'); } // Description length check if (schema.description) { const desc = typeof schema.description === 'string' ? schema.description : schema.description.en; if (desc && desc.length < 50) { this._addSuggestion('description', 'Description is quite short, consider adding more detail', 'best_practice', 'Aim for at least 50-100 characters for better SEO and understanding'); } } } /** * Extract entity info - SAME AS UI VALIDATOR * @private */ _extractEntityInfo(schema) { if (!schema.entityType || !schema.entityCategory) return null; const modules = schema.modules ? Object.keys(schema.modules) : []; return { entityType: schema.entityType, entityCategory: schema.entityCategory, subcategory: schema.subcategory, baseSchema: schema.entityCategory, modules, hasEntityCapabilities: !!schema.entityCapabilities, hasSiteCapabilities: !!schema.siteCapabilities }; } /** * Build validation result - SAME AS UI VALIDATOR * @private */ _buildResult(isValid, entityInfo, schema) { const score = this._calculateScore(schema); const completeness = this._calculateCompleteness(schema); const performance = this._calculatePerformance(schema); return { isValid, errors: this.errors, warnings: this.warnings, suggestions: this.suggestions, entityInfo, score, completeness, performance }; } /** * Calculate score using META-AIML Intelligent Scoring Engine - SAME AS UI VALIDATOR * @private */ _calculateScore(schema) { const errorWeight = 30; const warningWeight = 10; const suggestionWeight = 5; // Базовый расчет штрафов const deductions = (this.errors.length * errorWeight) + (this.warnings.length * warningWeight) + (this.suggestions.length * suggestionWeight); const baseScore = Math.max(0, 100 - deductions); // 🎯 PAGESPEED-ПОДОБНАЯ СИСТЕМА СКОРИНГА (META-AIML Intelligent Scoring Engine) // 🟢 EXCELLENT ZONE (90-100): Нет warnings - качественная схема if (this.warnings.length === 0) { // Если нет warnings, стартуем с 90 и учитываем completeness для достижения 100 const completeness = this._calculateCompleteness(schema); const excellentScore = 90 + (completeness * 0.1); // 10% влияния completeness return Math.min(100, Math.max(90, excellentScore)); } // 🟡 GOOD ZONE (50-89): Есть errors, но схема функциональная if (this.errors.length > 0) { // Если много критических ошибок (>3), может упасть в Poor зону if (this.errors.length > 3) { return Math.max(25, baseScore); // Дно на уровне 25 } // Иначе минимум Good зона return Math.max(50, baseScore); } // 🟡 GOOD ZONE (50-89): Нет errors, но есть warnings return Math.max(50, baseScore); } /** * Calculate completeness using same logic as UI validator - SAME AS UI VALIDATOR * @private */ _calculateCompleteness(schema) { if (!schema) return 0; // Согласно required_fields_v2.0.1.md - критически обязательные поля (ERRORS) const criticalFields = [ '@context', // ОБЯЗАТЕЛЬНО точное значение '@id', // Уникальный URI идентификатор '@type', // Pascal Case название типа 'schemaVersion', // ОБЯЗАТЕЛЬНО "2.0.1" 'entityType', // snake_case один из 31 типов 'entityCategory',// один из 6 базовых категорий 'subcategory', // должна соответствовать entityType 'name', // Мультиязычные названия (минимум "en") 'description' // Мультиязычные описания (минимум "en", 50+ символов) ]; // Настоятельно рекомендуемые поля (WARNINGS) const recommendedFields = [ 'url', // Валидный HTTP/HTTPS URL 'shortDescription', // Краткое описание в одну строку 'logo' // Для видимых сущностей ]; // НОВЫЕ ПОЛЯ v2.0.1 - объективные возможности const newV201Fields = [ 'entityCapabilities', // Объективные возможности бизнеса 'siteCapabilities' // Возможности веб-сайта ]; // Дополнительные поля для полноты const enhancementFields = [ 'properties', 'modules', 'foundingDate', 'lastModified' ]; let totalWeight = 0; let currentWeight = 0; // Критические поля - 50% веса (если нет - критическая ошибка) const criticalWeight = 50; totalWeight += criticalWeight; let criticalPresent = 0; criticalFields.forEach(field => { if (schema[field] !== undefined) { // Дополнительная проверка качества для name и description if (field === 'name' || field === 'description') { if (typeof schema[field] === 'object' && schema[field] !== null) { const langObj = schema[field]; if (langObj['en'] && langObj['en'].length > 0) { if (field === 'description' && langObj['en'].length >= 50) { criticalPresent++; } else if (field === 'name') { criticalPresent++; } } } } else { criticalPresent++; } } }); currentWeight += (criticalPresent / criticalFields.length) * criticalWeight; // Рекомендуемые поля - 25% веса const recommendedWeight = 25; totalWeight += recommendedWeight; let recommendedPresent = 0; recommendedFields.forEach(field => { if (schema[field] !== undefined) { // Дополнительная проверка для URL if (field === 'url') { const url = schema[field]; if (url && (url.startsWith('http://') || url.startsWith('https://'))) { recommendedPresent++; } } else { recommendedPresent++; } } }); currentWeight += (recommendedPresent / recommendedFields.length) * recommendedWeight; // НОВЫЕ ПОЛЯ v2.0.1 - 15% веса (важно для современных схем) const newFieldsWeight = 15; totalWeight += newFieldsWeight; let newFieldsPresent = 0; newV201Fields.forEach(field => { if (schema[field] !== undefined) { const capabilities = schema[field]; // Проверяем что не просто {}, а содержит данные if (capabilities && Object.keys(capabilities).length > 0) { newFieldsPresent++; } } }); currentWeight += (newFieldsPresent / newV201Fields.length) * newFieldsWeight; // Дополнительные поля для достижения 100% - 10% веса const enhancementWeight = 10; totalWeight += enhancementWeight; let enhancementPresent = 0; enhancementFields.forEach(field => { if (schema[field] !== undefined) { if (field === 'modules') { const modules = schema[field]; // Проверяем что есть хотя бы один включенный модуль if (modules && Object.keys(modules).length > 0) { enhancementPresent++; } } else { enhancementPresent++; } } }); currentWeight += (enhancementPresent / enhancementFields.length) * enhancementWeight; return Math.round((currentWeight / totalWeight) * 100); } /** * Calculate performance - SAME AS UI VALIDATOR * @private */ _calculatePerformance(schema) { if (!schema) return { schemaSize: 0, complexity: 'low', moduleCount: 0 }; const schemaSize = JSON.stringify(schema).length; const moduleCount = schema.modules ? Object.keys(schema.modules).length : 0; let complexity = 'low'; if (moduleCount > 5 || schemaSize > 5000) complexity = 'high'; else if (moduleCount > 2 || schemaSize > 2000) complexity = 'medium'; return { schemaSize, complexity, moduleCount }; } /** * Add error - SAME AS UI VALIDATOR * @private */ _addError(field, message, category, suggestion) { this.errors.push({ field, message, severity: 'error', category, suggestion }); } /** * Add warning - SAME AS UI VALIDATOR * @private */ _addWarning(field, message, category, suggestion) { this.warnings.push({ field, message, severity: 'warning', category, suggestion }); } /** * Add suggestion - SAME AS UI VALIDATOR * @private */ _addSuggestion(field, message, category, suggestion) { this.suggestions.push({ field, message, severity: 'info', category, suggestion }); } } // Static validation method - convenience method AIMLParser.validate = (data, options = {}) => { const parser = new AIMLParser(options); return parser.validate(data); }; // Static factory methods AIMLParser.createProduction = () => new AIMLParser({ debug: false, strict: true }); AIMLParser.createDevelopment = () => new AIMLParser({ debug: true, strict: false }); // Utility methods AIMLParser.getVersion = () => AIML_VERSION; AIMLParser.getEntityTypes = () => { const allTypes = []; Object.values(ENTITY_TYPES).forEach(types => { allTypes.push(...types); }); return allTypes.sort(); }; AIMLParser.getEntityCategories = () => BASE_CATEGORIES; AIMLParser.getModules = () => AVAILABLE_MODULES; AIMLParser.getSubcategories = () => Object.keys(SUBCATEGORIES); // Get required modules for entity type - ADDED from CHANGELOG.md line 90 AIMLParser.getRequiredModules = (entityType) => { if (!entityType || typeof entityType !== 'string') { return []; } return REQUIRED_MODULES[entityType] || []; }; AIMLParser.validateConfig = (options) => options && typeof options === 'object'; // Additional static methods for convenience AIMLParser.isValid = (data, options = {}) => { const result = AIMLParser.validate(data, options); return result.isValid; }; AIMLParser.getEntityInfo = (data) => { try { const parser = new AIMLParser(); return parser._extractEntityInfo(data); } catch { return null; } }; // Export module.exports = AIMLParser;