lincd
Version:
LINCD is a JavaScript library for building user interfaces with linked data (also known as 'structured data', or RDF)
196 lines • 7.66 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.linkedProperty = exports.objectProperty = exports.literalProperty = void 0;
exports.registerLinkedProperty = registerLinkedProperty;
exports.onShapeSetup = onShapeSetup;
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
const models_js_1 = require("../models.js");
const SHACL_js_1 = require("../shapes/SHACL.js");
const shacl_js_1 = require("../ontologies/shacl.js");
const List_js_1 = require("../shapes/List.js");
const literalProperty = (config) => {
return _linkedProperty(config, shacl_js_1.shacl.Literal);
};
exports.literalProperty = literalProperty;
const objectProperty = (config) => {
return _linkedProperty(config, shacl_js_1.shacl.IRI);
};
exports.objectProperty = objectProperty;
/**
* The most general decorator to indicate a get/set method requires & provides a certain linked data property.
* Using this generator generates a [SHACL Property Shape](https://www.w3.org/TR/shacl/#property-shapes)
* @param config - configures the property shape with a plain javascript object that follows the [PropertyShapeConfig](/docs/lincd.js/interfaces/utils_ShapeDecorators.PropertyShapeConfig) interface.
*
* @example
* ```
* \@linkedProperty({
* path:foaf.name,
* required:true,
* nodeKind:Literal,
* maxLength:1,
* defaultValue:"John"
* })
* get name(){
* return this.getValue(foaf.name) || "John"
* }
* ```
*/
const linkedProperty = (config) => {
return _linkedProperty(config);
};
exports.linkedProperty = linkedProperty;
const _linkedProperty = (config, defaultNodeKind = null) => {
return function (target, propertyKey, descriptor) {
//if the shape has already been initiated (with linkedShape)
//Note that the constructor may have shape defined if the class that it extends is already decorated with linkedShape
//so we need to check hasOwnProperty
let shape = target.constructor.hasOwnProperty('shape')
? target.constructor
: null;
//then we pass the shape and it will be used to register the property shape
let propertyShape = registerLinkedProperty(config, propertyKey, shape, defaultNodeKind);
if (!shape) {
//but if it was not yet available, then store property shapes in a temporary array in the constructor
//this is picked up in Module.ts and put into the Shape when its ready
if (!target.constructor['propertyShapes']) {
target.constructor['propertyShapes'] = [];
}
target.constructor['propertyShapes'].push(propertyShape);
}
};
};
function registerLinkedProperty(config, propertyKey, shape, defaultNodeKind = null) {
let propertyShape = new SHACL_js_1.PropertyShape();
propertyShape.path = config.path;
propertyShape.label = propertyKey;
if (config.required) {
propertyShape.minCount = 1;
}
else if (config.minCount) {
propertyShape.minCount = config.minCount;
}
if (config.maxCount) {
propertyShape.maxCount = config.maxCount;
}
if (config['dataType']) {
propertyShape.datatype = config['dataType'];
}
if (config.nodeKind) {
let nodeKind = config.nodeKind;
//for @linkedProperty, nodeKind will be Literal
if (nodeKind === models_js_1.Literal) {
propertyShape.nodeKind = shacl_js_1.shacl.Literal;
}
//for @objectProperty, by default nodeKind will be NamedNode
// stored as shacl.IRI
if (nodeKind === models_js_1.NamedNode) {
propertyShape.nodeKind = shacl_js_1.shacl.IRI;
}
if (nodeKind === models_js_1.BlankNode) {
propertyShape.nodeKind = shacl_js_1.shacl.BlankNode;
}
if (Array.isArray(nodeKind)) {
if (nodeKind.includes(models_js_1.BlankNode) && nodeKind.includes(models_js_1.NamedNode)) {
propertyShape.nodeKind = shacl_js_1.shacl.BlankNodeOrIRI;
}
if (nodeKind.includes(models_js_1.Literal) && nodeKind.includes(models_js_1.NamedNode)) {
propertyShape.nodeKind = shacl_js_1.shacl.IRIOrLiteral;
}
if (nodeKind.includes(models_js_1.Literal) && nodeKind.includes(models_js_1.BlankNode)) {
propertyShape.nodeKind = shacl_js_1.shacl.BlankNodeOrLiteral;
}
}
}
else {
//if no nodeKind was provided, use the default, if given
if (defaultNodeKind) {
propertyShape.nodeKind = defaultNodeKind;
}
}
//we accept a shape configuration, which translates to a sh:nodeShape
if (config.shape) {
//if this shape class has already got a NodeShape connected to it
if (config.shape['shape']) {
//then we can use this NodeShape now as the value of nodeShape for this property shape
propertyShape.valueShape = config.shape['shape'];
}
else {
//however the shape class may not have run its decorators yet
//so in that case we temporarily store a reference
//which gets processed in Module:linkedShape()
if (!config.shape['nodeShapeOf']) {
config.shape['nodeShapeOf'] = [];
}
config.shape['nodeShapeOf'].push(propertyShape);
}
}
if (config.in) {
//assuming config.in is a NodeSet already:
propertyShape.inList = List_js_1.List.createFrom(config.in);
}
if (config.editInline) {
propertyShape.editInline = config.editInline;
}
// console.log('Property method ' + config.path.toString() + ' initialised.');
// if (!target.constructor.shape) {
// console.log('Creating shape from method decorators.');
// target.constructor.shape = new NodeShape();
// }
//see above why shape may not be provided
if (shape) {
//update the URI (by extending the URI of the shape)
propertyShape.namedNode.uri = shape.namedNode.uri + `/${propertyKey}`;
//then add it directly
shape.addPropertyShape(propertyShape);
}
return propertyShape;
//
//sh.property
// (NamedNode value must have this type, like range but restrictive)
//sh.class
// (Literal value must have this datatype, like range)
//sh.dataType
//
//sh.optional
//
//sh.path
// (values must have this node type. Choose from: sh:NodeKind: sh:BlankNode,sh:IRI, sh:Literal, sh:BlankNodeOrIRI, sh:BlankNodeOrLiteral or sh:IRIOrLiteral)
//sh.nodeKind
// (cardinality, number, required properties would have minCount 1)
//sh.minCount
// (if only 1 value possible maxCount =1. Probably common)
//sh.maxCount
// (numbers)
//sh.minExclusive
//
//sh.minInclusive
//
//sh.maxExclusive
//
//sh.maxInclusive
// (must have exactly this value)
//sh.hasValue
// (specify possible values)
//sh.in
// (2 props must have different value)
//sh.disjoin
// (2 props must have same value)
//sh.equals
}
function onShapeSetup(target, callback) {
let constructor = target.constructor;
if (constructor.hasOwnProperty('shape')) {
callback(constructor.shape);
}
else {
if (!constructor['shapeCallbacks']) {
constructor['shapeCallbacks'] = [];
}
constructor['shapeCallbacks'].push(callback);
}
}
//# sourceMappingURL=ShapeDecorators.js.map