UNPKG

@agility/cli

Version:

Agility CLI for working with your content. (Public Beta)

328 lines 13.2 kB
"use strict"; /** * Content Field Validation Service * * Validates and sanitizes content fields before mapping to ensure: * - Proper reference types and structures * - Asset URL validity * - Content ID reference validation * - Field type compliance with Agility CMS expectations */ Object.defineProperty(exports, "__esModule", { value: true }); exports.ContentFieldValidator = void 0; exports.createContentFieldValidator = createContentFieldValidator; exports.validateField = validateField; var shared_1 = require("../shared"); var ContentFieldValidator = /** @class */ (function () { function ContentFieldValidator() { this.linkTypeDetector = new shared_1.LinkTypeDetector(); } /** * Validate all fields in a content item */ ContentFieldValidator.prototype.validateContentFields = function (fields, options) { var _a; if (options === void 0) { options = {}; } if (!fields || typeof fields !== 'object') { return { isValid: true, validatedFields: fields, totalWarnings: 0, totalErrors: 0, fieldResults: new Map() }; } var fieldResults = new Map(); var validatedFields = {}; var totalWarnings = 0; var totalErrors = 0; var overallValid = true; for (var _i = 0, _b = Object.entries(fields); _i < _b.length; _i++) { var _c = _b[_i], fieldKey = _c[0], fieldValue = _c[1]; var result = this.validateSingleField(fieldKey, fieldValue, options); fieldResults.set(fieldKey, result); validatedFields[fieldKey] = (_a = result.sanitizedField) !== null && _a !== void 0 ? _a : result.field; totalWarnings += result.warnings.length; totalErrors += result.errors.length; if (!result.isValid) { overallValid = false; } } return { isValid: overallValid, validatedFields: validatedFields, totalWarnings: totalWarnings, totalErrors: totalErrors, fieldResults: fieldResults }; }; /** * Validate a single field with type-specific rules */ ContentFieldValidator.prototype.validateSingleField = function (fieldKey, fieldValue, options) { var result = { isValid: true, field: fieldValue, warnings: [], errors: [] }; // Handle null/undefined - always valid if (fieldValue === null || fieldValue === undefined) { return result; } // Validate object fields (content references, nested structures) if (typeof fieldValue === 'object' && fieldValue !== null) { return this.validateObjectField(fieldKey, fieldValue, options); } // Validate string fields (asset URLs, text content) if (typeof fieldValue === 'string') { return this.validateStringField(fieldKey, fieldValue, options); } // Validate numeric fields if (typeof fieldValue === 'number') { return this.validateNumericField(fieldKey, fieldValue, options); } // Primitive fields (boolean, etc.) are always valid return result; }; /** * Validate object fields with content references */ ContentFieldValidator.prototype.validateObjectField = function (fieldKey, fieldValue, options) { var _this = this; var result = { isValid: true, field: fieldValue, warnings: [], errors: [] }; // Validate contentid/contentID references if ('contentid' in fieldValue || 'contentID' in fieldValue) { var contentId = fieldValue.contentid || fieldValue.contentID; if (typeof contentId !== 'number' || contentId <= 0) { result.errors.push("Invalid content ID: ".concat(contentId, " in field ").concat(fieldKey)); result.isValid = false; } } // Validate LinkedContentDropdown pattern if (fieldValue.referencename && fieldValue.sortids) { var sortIds = fieldValue.sortids.toString(); // Validate sortids format (comma-separated numbers) var ids = sortIds.split(',').map(function (id) { return id.trim(); }); var invalidIds = ids.filter(function (id) { return isNaN(parseInt(id)) || parseInt(id) <= 0; }); if (invalidIds.length > 0) { result.errors.push("Invalid sort IDs in field ".concat(fieldKey, ": ").concat(invalidIds.join(', '))); result.isValid = false; } // Validate reference name if containers are available if (options.sourceContainers) { var containerExists = options.sourceContainers.some(function (c) { return c.referenceName === fieldValue.referencename; }); if (!containerExists) { result.warnings.push("Container reference ".concat(fieldValue.referencename, " not found in field ").concat(fieldKey)); } } } // Validate gallery references if (fieldValue.mediaGroupingID) { var galleryId = fieldValue.mediaGroupingID; if (typeof galleryId !== 'number' || galleryId <= 0) { result.errors.push("Invalid gallery ID: ".concat(galleryId, " in field ").concat(fieldKey)); result.isValid = false; } } // Recursive validation for nested objects/arrays if (Array.isArray(fieldValue)) { fieldValue.forEach(function (item, index) { var _a, _b; if (typeof item === 'object' && item !== null) { var nestedResult = _this.validateObjectField("".concat(fieldKey, "[").concat(index, "]"), item, options); (_a = result.warnings).push.apply(_a, nestedResult.warnings); (_b = result.errors).push.apply(_b, nestedResult.errors); if (!nestedResult.isValid) { result.isValid = false; } } }); } return result; }; /** * Validate string fields */ ContentFieldValidator.prototype.validateStringField = function (fieldKey, fieldValue, options) { var result = { isValid: true, field: fieldValue, warnings: [], errors: [] }; // Validate asset URLs if (fieldValue.includes('cdn.aglty.io')) { if (!this.isValidAssetUrl(fieldValue)) { result.errors.push("Invalid asset URL format in field ".concat(fieldKey, ": ").concat(fieldValue)); result.isValid = false; } else if (options.sourceAssets) { // Check if asset exists in source data var assetExists = options.sourceAssets.some(function (asset) { return asset.originUrl === fieldValue || asset.url === fieldValue || asset.edgeUrl === fieldValue; }); if (!assetExists) { result.warnings.push("Asset URL not found in source data for field ".concat(fieldKey, ": ").concat(fieldValue)); } } } // Validate content ID strings (CategoryID, ValueField patterns) if (this.isContentIdField(fieldKey, fieldValue)) { var contentIds = fieldValue.includes(',') ? fieldValue.split(',').map(function (id) { return id.trim(); }) : [fieldValue.trim()]; var invalidIds = contentIds.filter(function (id) { return isNaN(parseInt(id)) || parseInt(id) <= 0; }); if (invalidIds.length > 0) { result.errors.push("Invalid content IDs in field ".concat(fieldKey, ": ").concat(invalidIds.join(', '))); result.isValid = false; } } // Validate against maximum field length if (fieldValue.length > 10000) { // Agility CMS typical max field length result.warnings.push("Field ".concat(fieldKey, " exceeds recommended length (").concat(fieldValue.length, " chars)")); } return result; }; /** * Validate numeric fields */ ContentFieldValidator.prototype.validateNumericField = function (fieldKey, fieldValue, options) { var result = { isValid: true, field: fieldValue, warnings: [], errors: [] }; // Validate range for ID fields if (fieldKey.toLowerCase().includes('id') || fieldKey.toLowerCase().includes('contentid')) { if (fieldValue <= 0) { result.errors.push("Invalid ID value in field ".concat(fieldKey, ": ").concat(fieldValue)); result.isValid = false; } } return result; }; /** * Check if string field contains content ID references */ ContentFieldValidator.prototype.isContentIdField = function (fieldKey, fieldValue) { var lowercaseKey = fieldKey.toLowerCase(); return (lowercaseKey.includes('categoryid') || lowercaseKey.includes('valuefield') || lowercaseKey.includes('tags') || lowercaseKey.includes('links')) && /^\d+(,\d+)*$/.test(fieldValue.trim()); }; /** * Validate asset URL format */ ContentFieldValidator.prototype.isValidAssetUrl = function (url) { try { var urlObj = new URL(url); return urlObj.hostname.includes('cdn.aglty.io') && urlObj.pathname.length > 1; } catch (_a) { return false; } }; /** * Sanitize field value to ensure compatibility */ ContentFieldValidator.prototype.sanitizeField = function (fieldKey, fieldValue) { var _this = this; if (fieldValue === null || fieldValue === undefined) { return fieldValue; } // Sanitize string fields if (typeof fieldValue === 'string') { // Trim whitespace var sanitized = fieldValue.trim(); // Remove null characters sanitized = sanitized.replace(/\0/g, ''); // Ensure proper encoding for special characters try { sanitized = decodeURIComponent(encodeURIComponent(sanitized)); } catch (_a) { // If encoding fails, return original return fieldValue; } return sanitized; } // Sanitize numeric fields if (typeof fieldValue === 'number') { // Ensure finite numbers if (!Number.isFinite(fieldValue)) { return 0; } return fieldValue; } // Sanitize object fields recursively if (typeof fieldValue === 'object' && fieldValue !== null) { if (Array.isArray(fieldValue)) { return fieldValue.map(function (item, index) { return _this.sanitizeField("".concat(fieldKey, "[").concat(index, "]"), item); }); } else { var sanitized = {}; for (var _i = 0, _b = Object.entries(fieldValue); _i < _b.length; _i++) { var _c = _b[_i], key = _c[0], value = _c[1]; sanitized[key] = this.sanitizeField("".concat(fieldKey, ".").concat(key), value); } return sanitized; } } return fieldValue; }; /** * Get validation summary for reporting */ ContentFieldValidator.prototype.getValidationSummary = function (fieldResults) { var summary = { totalFields: fieldResults.size, validFields: 0, fieldsWithWarnings: 0, fieldsWithErrors: 0, criticalFields: [] }; fieldResults.forEach(function (result, fieldKey) { if (result.isValid) { summary.validFields++; } if (result.warnings.length > 0) { summary.fieldsWithWarnings++; } if (result.errors.length > 0) { summary.fieldsWithErrors++; summary.criticalFields.push(fieldKey); } }); return summary; }; return ContentFieldValidator; }()); exports.ContentFieldValidator = ContentFieldValidator; /** * Factory function for easy usage */ function createContentFieldValidator() { return new ContentFieldValidator(); } /** * Quick validation function for single fields */ function validateField(fieldKey, fieldValue, options) { if (options === void 0) { options = {}; } var validator = new ContentFieldValidator(); return validator['validateSingleField'](fieldKey, fieldValue, options); } //# sourceMappingURL=content-field-validation.js.map