UNPKG

@jeswr/shacl2shex

Version:
134 lines (133 loc) 5.3 kB
"use strict"; /** * @fileoverview ShapeMap generation functionality for preserving SHACL target class information * @generated This file was generated by GitHub Copilot AI to resolve issue #283 */ Object.defineProperty(exports, "__esModule", { value: true }); exports.shapeMapFromDataset = shapeMapFromDataset; exports.writeShapeMap = writeShapeMap; const n3_1 = require("n3"); const rdf_namespaces_1 = require("rdf-namespaces"); const Shacl_shapeTypes_1 = require("./ldo/Shacl.shapeTypes"); const shapeFromDataset_1 = require("./shapeFromDataset"); const { namedNode, defaultGraph } = n3_1.DataFactory; /** * Extracts ShapeMap information from a SHACL dataset * * This function processes SHACL NodeShapes and generates corresponding ShapeMap entries * that preserve the target class information from sh:targetClass properties. * * @param shapeStore - The RDF store containing SHACL shapes * @returns A ShapeMap object containing the extracted mappings * * @example * ```typescript * import { shapeMapFromDataset } from './shapeMapFromDataset'; * * const store = // ... load SHACL data * const shapeMap = shapeMapFromDataset(store); * console.log(shapeMap); * // Output: { * // entries: [ * // { * // node: "FOCUS rdf:type ex:ClassOfProduct", * // shape: "ex:ClassOfProductShape" * // } * // ] * // } * ``` */ function shapeMapFromDataset(shapeStore) { const entries = []; // Find all NodeShapes in the dataset for (const { subject: shape } of shapeStore.match(null, namedNode(rdf_namespaces_1.rdf.type), namedNode(rdf_namespaces_1.shacl.NodeShape), defaultGraph())) { if (shape.termType !== 'NamedNode' && shape.termType !== 'BlankNode') { // eslint-disable-next-line no-continue continue; } try { // Extract shape-level data including targetClass const shapeData = (0, shapeFromDataset_1.shapeFromDataset)(Shacl_shapeTypes_1.ShapeShapeShapeType, shapeStore, shape); // If the shape has targetClass properties, create ShapeMap entries if (shapeData.targetClass && shapeData.targetClass.length > 0) { for (const targetClass of shapeData.targetClass) { entries.push({ node: `FOCUS rdf:type <${targetClass['@id']}>`, shape: shape.value, }); } } // Handle other target types if present if (shapeData.targetSubjectsOf && shapeData.targetSubjectsOf.length > 0) { for (const targetPredicate of shapeData.targetSubjectsOf) { entries.push({ node: `FOCUS <${targetPredicate['@id']}> _`, shape: shape.value, }); } } if (shapeData.targetObjectsOf && shapeData.targetObjectsOf.length > 0) { for (const targetPredicate of shapeData.targetObjectsOf) { entries.push({ node: `_ <${targetPredicate['@id']}> FOCUS`, shape: shape.value, }); } } } catch (e) { // If we can't extract shape data, skip this shape } } return { entries }; } /** * Converts a ShapeMap object to a human-readable string format * * @param shapeMap - The ShapeMap to serialize * @param prefixes - Optional prefix mappings for shorter URIs * @returns A string representation of the ShapeMap * * @example * ```typescript * const shapeMap = { entries: [{ node: "FOCUS rdf:type ex:Person", shape: "ex:PersonShape" }] }; * const output = writeShapeMap(shapeMap); * console.log(output); * // Output: "FOCUS rdf:type ex:Person@ex:PersonShape" * ``` */ function writeShapeMap(shapeMap, prefixes) { if (shapeMap.entries.length === 0) { return '# No shape mappings found\n'; } let output = '# @generated This file was generated by GitHub Copilot AI to test issue #283 resolution\n'; output += '# ShapeMap - Associates RDF nodes with validation shapes\n'; output += '# Based on: https://shexspec.github.io/shape-map/\n'; output += '# Format: {node pattern}@{shape}\n\n'; // Add prefix declarations if provided if (prefixes) { for (const [prefix, iri] of Object.entries(prefixes)) { if (prefix && prefix !== 'base') { output += `PREFIX ${prefix}: <${iri}>\n`; } } output += '\n'; } // Add each mapping for (const entry of shapeMap.entries) { let nodePattern = entry.node; let shapeId = entry.shape; // Apply prefix compression if available if (prefixes) { for (const [prefix, iri] of Object.entries(prefixes)) { if (prefix && prefix !== 'base') { const iriPattern = new RegExp(`<${iri.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}([^>]*)>`, 'g'); nodePattern = nodePattern.replace(iriPattern, `${prefix}:$1`); shapeId = shapeId.replace(iri, `${prefix}:`); } } } output += `{${nodePattern}}@${shapeId}\n`; } return output; }