unrdf
Version:
Production-ready RDF knowledge graph library with Knowledge Hooks, SPARC methodology, and Knowledge Substrate optimization
224 lines (222 loc) • 8.67 kB
JavaScript
import { Parser, Store } from "n3";
import rdf from "rdf-ext";
import SHACLValidator from "rdf-validate-shacl";
//#region src/knowledge-engine/validate.mjs
/**
* Validate a store against SHACL shapes.
* @param {Store} store - The store containing data to validate
* @param {Store|string} shapes - The store or Turtle string containing SHACL shapes
* @param {Object} [options] - Validation options
* @param {boolean} [options.strict] - Enable strict validation mode
* @param {boolean} [options.includeDetails] - Include detailed validation results
* @returns {{conforms: boolean, results: Array<object>}} Validation report
*
* @throws {Error} If validation fails
*
* @example
* const dataStore = new Store();
* // ... add data quads to store
*
* const shapesTtl = `
* @prefix sh: <http://www.w3.org/ns/shacl#> .
* @prefix ex: <http://example.org/> .
* ex:PersonShape a sh:NodeShape ;
* sh:targetClass ex:Person ;
* sh:property [
* sh:path ex:name ;
* sh:minCount 1 ;
* sh:maxCount 1
* ] .
* `;
*
* const report = validateShacl(dataStore, shapesTtl);
* console.log('Conforms:', report.conforms);
* console.log('Results:', report.results);
*/
function validateShacl(store, shapes, options = {}) {
if (!store || typeof store.getQuads !== "function") throw new TypeError("validateShacl: store must be a valid Store instance");
if (!shapes) throw new TypeError("validateShacl: shapes must be provided");
try {
const shapesStore = typeof shapes === "string" ? new Store(new Parser().parse(shapes)) : shapes;
if (!shapesStore || typeof shapesStore.getQuads !== "function") throw new TypeError("validateShacl: shapes must be a valid Store or Turtle string");
const validator = new SHACLValidator(rdf.dataset(shapesStore.getQuads()));
const report = validator.validate(rdf.dataset(store.getQuads()));
const results = (report.results || []).map((r) => ({
message: r.message?.[0]?.value || null,
path: r.path?.value || null,
focusNode: r.focusNode?.value || null,
severity: r.severity?.value || null,
sourceConstraint: r.sourceConstraint?.value || null,
sourceConstraintComponent: r.sourceConstraintComponent?.value || null,
sourceShape: r.sourceShape?.value || null,
value: r.value?.value || null,
...options.includeDetails && {
detail: r.detail || null,
resultPath: r.resultPath?.value || null,
resultSeverity: r.resultSeverity?.value || null
}
}));
return {
conforms: report.conforms,
results,
...options.includeDetails && {
totalResults: results.length,
errorCount: results.filter((r) => r.severity === "http://www.w3.org/ns/shacl#Violation").length,
warningCount: results.filter((r) => r.severity === "http://www.w3.org/ns/shacl#Warning").length,
infoCount: results.filter((r) => r.severity === "http://www.w3.org/ns/shacl#Info").length
}
};
} catch (error) {
throw new Error(`SHACL validation failed: ${error.message}`);
}
}
/**
* Validate a store against multiple SHACL shape sets.
* @param {Store} store - The store containing data to validate
* @param {Array<Store|string>} shapesList - Array of stores or Turtle strings containing SHACL shapes
* @param {Object} [options] - Validation options
* @returns {{conforms: boolean, results: Array<object>, shapeResults: Array<object>}} Combined validation report
*
* @throws {Error} If validation fails
*
* @example
* const shapesList = [
* personShapesTtl,
* organizationShapesTtl,
* contactShapesTtl
* ];
*
* const report = validateShaclMultiple(store, shapesList);
* console.log('Overall conforms:', report.conforms);
* console.log('Shape-specific results:', report.shapeResults);
*/
function validateShaclMultiple(store, shapesList, options = {}) {
if (!store || typeof store.getQuads !== "function") throw new TypeError("validateShaclMultiple: store must be a valid Store instance");
if (!Array.isArray(shapesList) || shapesList.length === 0) throw new TypeError("validateShaclMultiple: shapesList must be a non-empty array");
try {
const shapeResults = [];
let allResults = [];
let overallConforms = true;
for (let i = 0; i < shapesList.length; i++) {
const shapes = shapesList[i];
const report = validateShacl(store, shapes, options);
shapeResults.push({
index: i,
shapes: typeof shapes === "string" ? "Turtle string" : "Store",
conforms: report.conforms,
resultCount: report.results.length,
results: report.results
});
allResults = allResults.concat(report.results);
if (!report.conforms) overallConforms = false;
}
return {
conforms: overallConforms,
results: allResults,
shapeResults,
totalShapes: shapesList.length,
totalResults: allResults.length
};
} catch (error) {
throw new Error(`Multiple SHACL validation failed: ${error.message}`);
}
}
/**
* Create a SHACL validation report in a structured format.
* @param {Object} validationResult - Result from validateShacl
* @param {Object} [options] - Formatting options
* @param {boolean} [options.includeSummary] - Include summary statistics
* @param {boolean} [options.groupBySeverity] - Group results by severity
* @returns {Object} Formatted validation report
*
* @example
* const report = validateShacl(store, shapes);
* const formatted = formatValidationReport(report, {
* includeSummary: true,
* groupBySeverity: true
* });
*/
function formatValidationReport(validationResult, options = {}) {
if (!validationResult || typeof validationResult !== "object") throw new TypeError("formatValidationReport: validationResult must be an object");
const { results = [], conforms } = validationResult;
const { includeSummary = false, groupBySeverity = false } = options;
let formatted = {
conforms,
resultCount: results.length
};
if (includeSummary) {
const severityCounts = results.reduce((acc, result) => {
const severity = result.severity || "unknown";
acc[severity] = (acc[severity] || 0) + 1;
return acc;
}, {});
formatted.summary = {
totalResults: results.length,
severityCounts,
hasErrors: severityCounts["http://www.w3.org/ns/shacl#Violation"] > 0,
hasWarnings: severityCounts["http://www.w3.org/ns/shacl#Warning"] > 0,
hasInfo: severityCounts["http://www.w3.org/ns/shacl#Info"] > 0
};
}
if (groupBySeverity) formatted.resultsBySeverity = results.reduce((acc, result) => {
const severity = result.severity || "unknown";
if (!acc[severity]) acc[severity] = [];
acc[severity].push(result);
return acc;
}, {});
else formatted.results = results;
return formatted;
}
/**
* Check if a validation result contains any errors.
* @param {Object} validationResult - Result from validateShacl
* @returns {boolean} True if there are any validation errors
*
* @example
* const report = validateShacl(store, shapes);
* if (hasValidationErrors(report)) {
* console.log('Validation failed with errors');
* }
*/
function hasValidationErrors(validationResult) {
if (!validationResult || typeof validationResult !== "object") return false;
const { results = [] } = validationResult;
return results.some((result) => result.severity === "http://www.w3.org/ns/shacl#Violation");
}
/**
* Get validation errors from a validation result.
* @param {Object} validationResult - Result from validateShacl
* @returns {Array<Object>} Array of validation error objects
*
* @example
* const report = validateShacl(store, shapes);
* const errors = getValidationErrors(report);
* errors.forEach(error => {
* console.log(`Error: ${error.message} at ${error.focusNode}`);
* });
*/
function getValidationErrors(validationResult) {
if (!validationResult || typeof validationResult !== "object") return [];
const { results = [] } = validationResult;
return results.filter((result) => result.severity === "http://www.w3.org/ns/shacl#Violation");
}
/**
* Get validation warnings from a validation result.
* @param {Object} validationResult - Result from validateShacl
* @returns {Array<Object>} Array of validation warning objects
*
* @example
* const report = validateShacl(store, shapes);
* const warnings = getValidationWarnings(report);
* warnings.forEach(warning => {
* console.log(`Warning: ${warning.message} at ${warning.focusNode}`);
* });
*/
function getValidationWarnings(validationResult) {
if (!validationResult || typeof validationResult !== "object") return [];
const { results = [] } = validationResult;
return results.filter((result) => result.severity === "http://www.w3.org/ns/shacl#Warning");
}
//#endregion
export { formatValidationReport, getValidationErrors, getValidationWarnings, hasValidationErrors, validateShacl, validateShaclMultiple };
//# sourceMappingURL=validate-DHas2Unp.mjs.map