rdf-terms
Version:
Convenience functions for handling RDFJS terms
519 lines • 20.5 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.TRIPLE_TERM_NAMES = exports.QUAD_TERM_NAMES = void 0;
exports.getTerms = getTerms;
exports.getTermsNested = getTermsNested;
exports.getNamedTerms = getNamedTerms;
exports.collectNamedTerms = collectNamedTerms;
exports.forEachTerms = forEachTerms;
exports.forEachTermsNested = forEachTermsNested;
exports.filterTerms = filterTerms;
exports.filterTermsNested = filterTermsNested;
exports.filterQuadTermNames = filterQuadTermNames;
exports.filterQuadTermNamesNested = filterQuadTermNamesNested;
exports.mapTerms = mapTerms;
exports.mapTermsNested = mapTermsNested;
exports.reduceTerms = reduceTerms;
exports.reduceTermsNested = reduceTermsNested;
exports.everyTerms = everyTerms;
exports.everyTermsNested = everyTermsNested;
exports.someTerms = someTerms;
exports.someTermsNested = someTermsNested;
exports.getValueNestedPath = getValueNestedPath;
exports.matchTerm = matchTerm;
exports.matchPattern = matchPattern;
exports.matchPatternComplete = matchPatternComplete;
exports.matchPatternMappings = matchPatternMappings;
const rdf_data_factory_1 = require("rdf-data-factory");
const DF = new rdf_data_factory_1.DataFactory();
/**
* All available quad term names.
* @type {[string , string , string , string]}
*/
exports.QUAD_TERM_NAMES = ['subject', 'predicate', 'object', 'graph'];
/**
* All available triple term names.
* @type {[string , string , string]}
*/
exports.TRIPLE_TERM_NAMES = ['subject', 'predicate', 'object'];
/**
* Get all terms in the given quad.
* @param {BaseQuad} quad An RDFJS quad.
* @param {boolean} ignoreDefaultGraph If true and the quad has the default graph as graph,
* this term will not be returned in the array.
* (default: false)
* @return {Term[]} The available terms in the quad.
*/
function getTerms(quad, ignoreDefaultGraph) {
if (ignoreDefaultGraph && quad.graph.termType === 'DefaultGraph') {
return [quad.subject, quad.predicate, quad.object];
}
return [quad.subject, quad.predicate, quad.object, quad.graph];
}
/**
* Get all terms in the given quad, including nested quads.
* @param {BaseQuad} quad An RDFJS quad.
* @param {boolean} ignoreDefaultGraph If true and the quad has the default graph as graph,
* this term will not be returned in the array.
* (default: false)
* @return {Term[]} The available terms in the nested quad, excluding quad terms.
*/
function getTermsNested(quad, ignoreDefaultGraph) {
const terms = [];
for (const term of getTerms(quad, ignoreDefaultGraph)) {
if (term.termType === 'Quad') {
getTermsNested(term, ignoreDefaultGraph).forEach(subTerm => terms.push(subTerm));
}
else {
terms.push(term);
}
}
return terms;
}
/**
* Convert the given quad to an array of named terms.
* This is the reverse operation of {@link collectNamedTerms}.
* @param {BaseQuad} quad An RDFJS quad.
* @return {INamedTerm[]} An array of named terms.
*/
function getNamedTerms(quad) {
return [
{ key: 'subject', value: quad.subject },
{ key: 'predicate', value: quad.predicate },
{ key: 'object', value: quad.object },
{ key: 'graph', value: quad.graph },
];
}
/**
* Convert an array of named terms to an RDFJS quad.
* This is the reverse operation of {@link getNamedTerms}.
* @param {INamedTerm[]} namedTerms An array of named terms.
* @param {(termName: QuadTermName) => Term} defaultCb An optional callback for when
* certain terms are not available in the array.
* @param {RDF.DataFactory} dataFactory A custom data factory to create quads.
* @return {Q} The resulting RDFJS quad.
* @template Q The type of quad to output, defaults to RDF.Quad.
*/
function collectNamedTerms(namedTerms, defaultCb, dataFactory) {
const elements = {};
namedTerms.forEach((namedTerm) => elements[namedTerm.key] = namedTerm.value);
if (defaultCb) {
elements.subject = elements.subject || defaultCb('subject');
elements.predicate = elements.predicate || defaultCb('predicate');
elements.object = elements.object || defaultCb('object');
elements.graph = elements.graph || defaultCb('graph');
}
return (dataFactory || DF).quad(elements.subject, elements.predicate, elements.object, elements.graph);
}
/**
* Iterates over each term.
* @param {BaseQuad} quad An RDFJS quad.
* @param {(value: Term, key: QuadTermName} cb A callback function.
*/
function forEachTerms(quad, cb) {
cb(quad.subject, 'subject');
cb(quad.predicate, 'predicate');
cb(quad.object, 'object');
cb(quad.graph, 'graph');
}
/**
* Iterates over each leaf term, while recursing into quoted triples.
* @param {BaseQuad} quad An RDFJS quad.
* @param {(value: Term, key: QuadTermName} cb A callback function.
* @param QuadTermName[] keys The current key path.
*/
function forEachTermsNested(quad, cb, keys = []) {
if (quad.subject.termType === 'Quad') {
forEachTermsNested(quad.subject, cb, [...keys, 'subject']);
}
else {
cb(quad.subject, [...keys, 'subject']);
}
if (quad.predicate.termType === 'Quad') {
forEachTermsNested(quad.predicate, cb, [...keys, 'predicate']);
}
else {
cb(quad.predicate, [...keys, 'predicate']);
}
if (quad.object.termType === 'Quad') {
forEachTermsNested(quad.object, cb, [...keys, 'object']);
}
else {
cb(quad.object, [...keys, 'object']);
}
if (quad.graph.termType === 'Quad') {
forEachTermsNested(quad.graph, cb, [...keys, 'graph']);
}
else {
cb(quad.graph, [...keys, 'graph']);
}
}
/**
* Get all terms in the given quad that return true on the given filter function.
* @param {BaseQuad} quad A quad.
* @param {(value: Term, key: QuadTermName) => boolean} filter A filter callback.
* @return {Term[]} The list of matching terms.
*/
function filterTerms(quad, filter) {
const terms = [];
if (filter(quad.subject, 'subject')) {
terms.push(quad.subject);
}
if (filter(quad.predicate, 'predicate')) {
terms.push(quad.predicate);
}
if (filter(quad.object, 'object')) {
terms.push(quad.object);
}
if (filter(quad.graph, 'graph')) {
terms.push(quad.graph);
}
return terms;
}
/**
* Get all terms in the given quad that return true on the given filter function, while recursing into quoted triples.
* @param {BaseQuad} quad A quad.
* @param {(value: Term, key: QuadTermName) => boolean} filter A filter callback.
* @param QuadTermName[] keys The current key path.
* @return {Term[]} The list of matching terms.
*/
function filterTermsNested(quad, filter, keys = []) {
let terms = [];
if (quad.subject.termType === 'Quad') {
terms = [...terms, ...filterTermsNested(quad.subject, filter, [...keys, 'subject'])];
}
else {
if (filter(quad.subject, [...keys, 'subject'])) {
terms.push(quad.subject);
}
}
if (quad.predicate.termType === 'Quad') {
terms = [...terms, ...filterTermsNested(quad.predicate, filter, [...keys, 'predicate'])];
}
else {
if (filter(quad.predicate, [...keys, 'predicate'])) {
terms.push(quad.predicate);
}
}
if (quad.object.termType === 'Quad') {
terms = [...terms, ...filterTermsNested(quad.object, filter, [...keys, 'object'])];
}
else {
if (filter(quad.object, [...keys, 'object'])) {
terms.push(quad.object);
}
}
if (quad.graph.termType === 'Quad') {
terms = [...terms, ...filterTermsNested(quad.graph, filter, [...keys, 'graph'])];
}
else {
if (filter(quad.graph, [...keys, 'graph'])) {
terms.push(quad.graph);
}
}
return terms;
}
/**
* Get all quad term names in the given quad that return true on the given filter function.
* @param {BaseQuad} quad A quad.
* @param {(value: Term, key: QuadTermName, all: INamedTerm[]) => boolean} filter A filter callback.
* @return {QuadTermName[]} The list of matching quad term names.
*/
function filterQuadTermNames(quad, filter) {
const names = [];
if (filter(quad.subject, 'subject')) {
names.push('subject');
}
if (filter(quad.predicate, 'predicate')) {
names.push('predicate');
}
if (filter(quad.object, 'object')) {
names.push('object');
}
if (filter(quad.graph, 'graph')) {
names.push('graph');
}
return names;
}
/**
* Get all quad term names in the given quad that return true on the given filter function, while recursing into quoted triples.
* @param {BaseQuad} quad A quad.
* @param {(value: Term, key: QuadTermName, all: INamedTerm[]) => boolean} filter A filter callback.
* @param QuadTermName[] keys The current key path.
* @return {QuadTermName[]} The list of matching quad term names.
*/
function filterQuadTermNamesNested(quad, filter, keys = []) {
let names = [];
const keysS = [...keys, 'subject'];
if (quad.subject.termType === 'Quad') {
names = [...names, ...filterQuadTermNamesNested(quad.subject, filter, keysS)];
}
else {
if (filter(quad.subject, keysS)) {
names.push(keysS);
}
}
const keysP = [...keys, 'predicate'];
if (quad.predicate.termType === 'Quad') {
names = [...names, ...filterQuadTermNamesNested(quad.predicate, filter, keysP)];
}
else {
if (filter(quad.predicate, keysP)) {
names.push(keysP);
}
}
const keysO = [...keys, 'object'];
if (quad.object.termType === 'Quad') {
names = [...names, ...filterQuadTermNamesNested(quad.object, filter, keysO)];
}
else {
if (filter(quad.object, keysO)) {
names.push(keysO);
}
}
const keysG = [...keys, 'graph'];
if (quad.graph.termType === 'Quad') {
names = [...names, ...filterQuadTermNamesNested(quad.graph, filter, keysG)];
}
else {
if (filter(quad.graph, keysG)) {
names.push(keysG);
}
}
return names;
}
/**
* Map all terms of a quad.
* @param {Quad} quad An RDFJS quad.
* @param {(value: Term, key: QuadTermName) => Term} mapper A mapper function.
* @param {RDF.DataFactory} dataFactory A custom data factory to create quads.
* @return {Quad} A new RDFJS quad.
* @template Q The type of quad, defaults to RDF.Quad.
*/
function mapTerms(quad, mapper, dataFactory) {
return (dataFactory || DF).quad(mapper(quad.subject, 'subject'), mapper(quad.predicate, 'predicate'), mapper(quad.object, 'object'), mapper(quad.graph, 'graph'));
}
/**
* Map all terms of a quad, while recursing into quoted triples.
* @param {Quad} quad An RDFJS quad.
* @param {(value: Term, key: QuadTermName) => Term} mapper A mapper function.
* @param {RDF.DataFactory} dataFactory A custom data factory to create quads.
* @param QuadTermName[] keys The current key path.
* @return {Quad} A new RDFJS quad.
* @template Q The type of quad, defaults to RDF.Quad.
*/
function mapTermsNested(quad, mapper, dataFactory, keys = []) {
return (dataFactory || DF).quad(quad.subject.termType === 'Quad' ?
mapTermsNested(quad.subject, mapper, dataFactory, [...keys, 'subject']) :
mapper(quad.subject, [...keys, 'subject']), quad.predicate.termType === 'Quad' ?
mapTermsNested(quad.predicate, mapper, dataFactory, [...keys, 'predicate']) :
mapper(quad.predicate, [...keys, 'predicate']), quad.object.termType === 'Quad' ?
mapTermsNested(quad.object, mapper, dataFactory, [...keys, 'object']) :
mapper(quad.object, [...keys, 'object']), quad.graph.termType === 'Quad' ?
mapTermsNested(quad.graph, mapper, dataFactory, [...keys, 'graph']) :
mapper(quad.graph, [...keys, 'graph']));
}
/**
* Reduce all terms of a quad.
* @param {BaseQuad} quad An RDFJS quad.
* @param {(previousValue: U, currentValue: Term, key: QuadTermName) => U} reducer A reduce function.
* @param {U} initialValue The initial value.
* @return {U} The final value.
*/
function reduceTerms(quad, reducer, initialValue) {
let value = initialValue;
value = reducer(value, quad.subject, 'subject');
value = reducer(value, quad.predicate, 'predicate');
value = reducer(value, quad.object, 'object');
return reducer(value, quad.graph, 'graph');
}
/**
* Reduce all terms of a quad, while recursing into quoted triples.
* @param {BaseQuad} quad An RDFJS quad.
* @param {(previousValue: U, currentValue: Term, key: QuadTermName) => U} reducer A reduce function.
* @param {U} initialValue The initial value.
* @param QuadTermName[] keys The current key path.
* @return {U} The final value.
*/
function reduceTermsNested(quad, reducer, initialValue, keys = []) {
let value = initialValue;
if (quad.subject.termType === 'Quad') {
value = reduceTermsNested(quad.subject, reducer, value, [...keys, 'subject']);
}
else {
value = reducer(value, quad.subject, [...keys, 'subject']);
}
if (quad.predicate.termType === 'Quad') {
value = reduceTermsNested(quad.predicate, reducer, value, [...keys, 'predicate']);
}
else {
value = reducer(value, quad.predicate, [...keys, 'predicate']);
}
if (quad.object.termType === 'Quad') {
value = reduceTermsNested(quad.object, reducer, value, [...keys, 'object']);
}
else {
value = reducer(value, quad.object, [...keys, 'object']);
}
if (quad.graph.termType === 'Quad') {
value = reduceTermsNested(quad.graph, reducer, value, [...keys, 'graph']);
}
else {
value = reducer(value, quad.graph, [...keys, 'graph']);
}
return value;
}
/**
* Determines whether all terms satisfy the specified test.
* @param {BaseQuad} quad An RDFJS quad.
* @param {(value: Term, key: QuadTermName} checker A checker function.
* @return {boolean} If all terms satisfy the specified test.
*/
function everyTerms(quad, checker) {
return checker(quad.subject, 'subject')
&& checker(quad.predicate, 'predicate')
&& checker(quad.object, 'object')
&& checker(quad.graph, 'graph');
}
/**
* Determines whether all terms satisfy the specified test, while recursing into quoted triples.
* @param {BaseQuad} quad An RDFJS quad.
* @param {(value: Term, key: QuadTermName} checker A checker function.
* @param QuadTermName[] keys The current key path.
* @return {boolean} If all terms satisfy the specified test.
*/
function everyTermsNested(quad, checker, keys = []) {
return (quad.subject.termType === 'Quad' ?
everyTermsNested(quad.subject, checker, [...keys, 'subject']) :
checker(quad.subject, [...keys, 'subject']))
&& (quad.predicate.termType === 'Quad' ?
everyTermsNested(quad.predicate, checker, [...keys, 'predicate']) :
checker(quad.predicate, [...keys, 'predicate']))
&& (quad.object.termType === 'Quad' ?
everyTermsNested(quad.object, checker, [...keys, 'object']) :
checker(quad.object, [...keys, 'object']))
&& (quad.graph.termType === 'Quad' ?
everyTermsNested(quad.graph, checker, [...keys, 'graph']) :
checker(quad.graph, [...keys, 'graph']));
}
/**
* Determines whether at least one term satisfies the specified test.
* @param {BaseQuad} quad An RDFJS quad.
* @param {(value: Term, key: QuadTermName} checker A checker function.
* @return {boolean} If at least one term satisfies the specified test.
*/
function someTerms(quad, checker) {
return checker(quad.subject, 'subject')
|| checker(quad.predicate, 'predicate')
|| checker(quad.object, 'object')
|| checker(quad.graph, 'graph');
}
/**
* Determines whether at least one term satisfies the specified test, while recursing into quoted triples.
* @param {BaseQuad} quad An RDFJS quad.
* @param {(value: Term, key: QuadTermName} checker A checker function.
* @param QuadTermName[] keys The current key path.
* @return {boolean} If at least one term satisfies the specified test.
*/
function someTermsNested(quad, checker, keys = []) {
return (quad.subject.termType === 'Quad' ?
someTermsNested(quad.subject, checker, [...keys, 'subject']) :
checker(quad.subject, [...keys, 'subject']))
|| (quad.predicate.termType === 'Quad' ?
someTermsNested(quad.predicate, checker, [...keys, 'predicate']) :
checker(quad.predicate, [...keys, 'predicate']))
|| (quad.object.termType === 'Quad' ?
someTermsNested(quad.object, checker, [...keys, 'object']) :
checker(quad.object, [...keys, 'object']))
|| (quad.graph.termType === 'Quad' ?
someTermsNested(quad.graph, checker, [...keys, 'graph']) :
checker(quad.graph, [...keys, 'graph']));
}
/**
* Get the nested value inside a quoted triple by the given path of quad keys.
* @param term A term, that can be a quoted triple.
* @param keys A path of quad term names.
*/
function getValueNestedPath(term, keys) {
if (keys.length === 0) {
return term;
}
if (term.termType === 'Quad') {
return getValueNestedPath(term[keys[0]], keys.slice(1));
}
throw new Error(`Tried to get ${keys[0]} from term of type ${term.termType}`);
}
/**
* Check if the given terms match.
*
* At least one of the following must be true:
* * Term B is undefined.
* * Term B is a variable.
* * Term A and B are quads, and return true for `matchPatternComplete`.
* * Quad term and term are equal (`termB.equals(termA)` return true)
*
* @param termA A term.
* @param termB An optional term.
*/
function matchTerm(termA, termB) {
return !termB
|| termB.termType === 'Variable'
|| (termB.termType === 'Quad' && termA.termType === 'Quad' && matchPatternComplete(termA, termB))
|| termB.equals(termA);
}
/**
* Check if the given quad matches with the given quad terms.
*
* Each term must match at least one of the following:
* * Term is undefined.
* * Term is a variable.
* * Quad term and term are both quads, and return true for `matchPatternComplete`.
* * Quad term and term are equal (`quadTerm.equals(term)` return true)
*
* @param {BaseQuad} quad A quad to match with (can not contain variables).
* @param {Term} subject An optional subject.
* @param {Term} predicate An optional predicate.
* @param {Term} object An optional object.
* @param {Term} graph An optional graph.
* @return {boolean} If the quad matches with the quad terms.
*/
function matchPattern(quad, subject, predicate, object, graph) {
return matchTerm(quad.subject, subject)
&& matchTerm(quad.predicate, predicate)
&& matchTerm(quad.object, object)
&& matchTerm(quad.graph, graph);
}
/**
* Check if the first quad matches with all terms from the second quad.
*
* Each term must match at least one of the following:
* * Quad2 term is a variable.
* * Quad1 term and Quad2 term are equal (`term1.equals(term2)` return true)
*
* @param {BaseQuad} quad A quad (can not contain variables).
* @param {BaseQuad} pattern A quad pattern (can contain variables).
* @return {boolean} If the quad terms match.
*/
function matchPatternComplete(quad, pattern) {
return matchPattern(quad, pattern.subject, pattern.predicate, pattern.object, pattern.graph);
}
function matchPatternMappings(quad, pattern, opt = {}) {
const map = {};
function match(_pattern, _quad) {
return everyTerms(_pattern, (t1, key) => {
var _a, _b;
const t2 = _quad[key];
switch (t1.termType) {
case 'Variable':
return (opt.skipVarMapping && t2.termType === 'Variable')
|| ((_b = (_a = map[t1.value]) === null || _a === void 0 ? void 0 : _a.equals(t2)) !== null && _b !== void 0 ? _b : (map[t1.value] = t2, true));
case 'Quad':
return t2.termType === 'Quad' && match(t1, t2);
default:
return t1.equals(t2);
}
});
}
return match(pattern, quad) && (opt.returnMappings ? map : true);
}
//# sourceMappingURL=QuadTermUtil.js.map