@sofianedjerbi/knowledge-tree-mcp
Version:
MCP server for hierarchical project knowledge management
146 lines • 5.31 kB
JavaScript
/**
* Validation utilities for Knowledge Tree MCP
* Handles all validation logic for knowledge entries, paths, and relationships
*/
import { PRIORITY_LEVELS, RELATIONSHIP_TYPES, BIDIRECTIONAL_RELATIONSHIPS, isValidPriority as isValidPriorityConst, isValidRelationshipType, isBidirectionalRelationship as isBidirectionalRelationshipConst, VALIDATION_CONSTANTS, Constants } from '../constants/index.js';
// Re-export validation functions from constants for backward compatibility
export const isValidPriority = isValidPriorityConst;
export const isValidRelationship = isValidRelationshipType;
export const isBidirectionalRelationship = isBidirectionalRelationshipConst;
// Re-export constants for backward compatibility (will be deprecated)
export const VALID_PRIORITIES = PRIORITY_LEVELS;
export const VALID_RELATIONSHIPS = RELATIONSHIP_TYPES;
export { BIDIRECTIONAL_RELATIONSHIPS };
/**
* Validates a path format
* @param path - Path to validate
* @returns Validation result with error message if invalid
*/
export function validatePath(path) {
if (!path || typeof path !== 'string' || path.trim() === '') {
return { valid: false, error: 'Path is required and must be non-empty' };
}
// Ensure valid path characters using constant regex
if (!VALIDATION_CONSTANTS.PATH_REGEX.test(path)) {
return {
valid: false,
error: Constants.ERRORS.INVALID_PATH
};
}
return { valid: true };
}
/**
* Validates that a filename matches the priority prefix
* @param filename - Filename to check
* @param priority - Expected priority
* @returns Validation result with error message if invalid
* @deprecated Priority is no longer part of the filename, only a JSON attribute
*/
export function validateFilenameMatchesPriority(filename, priority) {
// Priority is no longer part of the filename
return { valid: true };
}
/**
* Validates required fields for a knowledge entry
* @param entry - Partial knowledge entry to validate
* @returns Array of validation errors
*/
export function validateRequiredFields(entry) {
const errors = [];
if (!entry.title || typeof entry.title !== 'string' || entry.title.trim() === '') {
errors.push('Title is required and must be non-empty');
}
if (!entry.priority || !isValidPriority(entry.priority)) {
errors.push(Constants.ERRORS.INVALID_PRIORITY);
}
if (!entry.problem || typeof entry.problem !== 'string' || entry.problem.trim() === '') {
errors.push('Problem description is required and must be non-empty');
}
if (!entry.solution || typeof entry.solution !== 'string' || entry.solution.trim() === '') {
errors.push('Solution description is required and must be non-empty');
}
return errors;
}
/**
* Validates relationships in a knowledge entry
* @param relationships - Array of relationships to validate
* @returns Array of validation errors
*/
export function validateRelationships(relationships) {
const errors = [];
if (!relationships || !Array.isArray(relationships)) {
return errors;
}
for (let i = 0; i < relationships.length; i++) {
const link = relationships[i];
if (!link.path || typeof link.path !== 'string') {
errors.push(`Related entry ${i + 1}: path is required`);
}
else {
const pathValidation = validatePath(link.path);
if (!pathValidation.valid) {
errors.push(`Related entry ${i + 1}: ${pathValidation.error}`);
}
}
if (!link.relationship || !isValidRelationship(link.relationship)) {
errors.push(`Related entry ${i + 1}: invalid relationship type`);
}
}
return errors;
}
/**
* Validates a complete knowledge entry
* @param entry - Knowledge entry to validate
* @param path - Path where the entry will be stored
* @returns Object with validation result and errors
*/
export function validateKnowledgeEntry(entry, path) {
const errors = [];
// Validate path
const pathValidation = validatePath(path);
if (!pathValidation.valid && pathValidation.error) {
errors.push(pathValidation.error);
}
// Validate required fields
errors.push(...validateRequiredFields(entry));
// Priority is no longer part of the filename - removed validation
// Validate relationships
if (entry.related_to) {
errors.push(...validateRelationships(entry.related_to));
}
return {
valid: errors.length === 0,
errors
};
}
/**
* Validates JSON format
* @param content - String content to validate as JSON
* @returns Validation result with parsed data or error
*/
export function validateJSON(content) {
try {
const data = JSON.parse(content);
return { valid: true, data };
}
catch (error) {
return {
valid: false,
error: 'Invalid JSON format'
};
}
}
/**
* Escapes HTML special characters
* @param text - Text to escape
* @returns Escaped HTML string
*/
export function escapeHtml(text) {
return text
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
//# sourceMappingURL=validation.js.map