@agility/cli
Version:
Agility CLI for working with your content. (Public Beta)
328 lines • 13.2 kB
JavaScript
;
/**
* 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