lincd
Version:
LINCD is a JavaScript library for building user interfaces with linked data (also known as 'structured data', or RDF)
147 lines • 8.21 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.TestNode = exports.createTraceShape = void 0;
const Shape_js_1 = require("../shapes/Shape.js");
const models_js_1 = require("../models.js");
const rdfs_js_1 = require("../ontologies/rdfs.js");
const NodeSet_js_1 = require("../collections/NodeSet.js");
function createTraceShape(shapeClass, shapeInstance, debugName) {
let detectionClass = class extends shapeClass {
constructor(p) {
super(p);
this.requested = [];
// resultOrigins:CoreMap<any,any> = new CoreMap();
this.usedAccessors = [];
this.responses = [];
}
};
let traceShape;
if (!shapeInstance) {
//if not provided we create a new detectionClass instance
let dummyNode = new TestNode();
traceShape = new detectionClass(dummyNode);
}
else {
//if an instance was provided
// (this happens if a testnode generates a testnode value on demand
// and the original shape get-accessor returns an instance of a shape of that testnode)
//then we turn that shape instance into it's test/detection variant
traceShape = new detectionClass(shapeInstance.namedNode);
}
//here in the constructor (now that we have a 'this')
//we will overwrite all the methods of the class we extend and the classes that it itself extends
//we start with the shape class itself
let finger = shapeClass;
while (finger) {
//check that this shape class or one of its superclasses still extends Shape, otherwise break;
if (!(finger.prototype instanceof Shape_js_1.Shape) || finger === Shape_js_1.Shape) {
break;
}
//get all the property descriptors of the class
let descriptors = Object.getOwnPropertyDescriptors(finger.prototype);
for (var key in descriptors) {
let descriptor = descriptors[key];
if (descriptor.configurable) {
//if this is a get method that used a @linkedProperty decorator
//then it should match with a propertyShape
let propertyShape = finger['shape']
.getPropertyShapes()
.find((propertyShape) => propertyShape.label === key);
//get the get method (that's the one place that we support @linkedProperty decorators for, for now)
let g = descriptor.get != null;
if (g) {
let newDescriptor = {};
newDescriptor.enumerable = descriptor.enumerable;
newDescriptor.configurable = descriptor.configurable;
//not sure if we can or want to?..
// newDescriptor.value= descriptor.value;
// newDescriptor.writable = descriptor.writable;
if (propertyShape) {
//create a new get function
newDescriptor.get = ((key, propertyShape, descriptor) => {
// console.log(debugName + ' requested get ' + key + ' - ' + propertyShape.path.value);
//use dummyShape as 'this'
let returnedValue = descriptor.get.call(traceShape);
// console.log('generated result -> ',res['print'] ? res['print']() : res);
// console.log('\tresult -> ', returnedValue && returnedValue.print ? returnedValue.print() : returnedValue);
//if a shape was returned, make sure we trace that shape too
if (returnedValue instanceof Shape_js_1.Shape) {
returnedValue = createTraceShape(Object.getPrototypeOf(returnedValue).constructor, returnedValue, Object.getPrototypeOf(returnedValue).constructor.name);
}
//store which property shapes were requested in the detectionClass defined above
traceShape.requested.push(propertyShape);
traceShape.usedAccessors.push(descriptor.get);
traceShape.responses.push(returnedValue);
//also store which result was returned for which property shape (we need this in Component.to().. / bindComponentToData())
// traceShape.resultOrigins.set(returnedValue,descriptor.get);
// returnedValue['_reqPropShape'] = propertyShape;
// returnedValue['_accessor'] = descriptor.get;
return returnedValue;
}).bind(detectionClass.prototype, key, propertyShape, descriptor);
}
else {
//if no propertyShape was found, then this is a get method that was not decorated with @linkedProperty
newDescriptor.get = () => {
var _a;
let numRequested = traceShape.requested.length;
//so we call the method as it was
let result = descriptor.get.call(traceShape);
//and if no new property shapes have been accessed
if (traceShape.requested.length === numRequested) {
//then probably someone forgot to add a @linkedProperty decorator!
//or at least it won't add any data to the dataRequest of the linked component, so let's warn the developer of that
console.warn(`"${(_a = traceShape.nodeShape) === null || _a === void 0 ? void 0 : _a.label}.${descriptor.get.name.replace('get ', '')}" was requested by a linked component. However '${descriptor.get.name}' is not decorated with a linked property decorator (like @linkedProperty), so LINCD can not automatically load this data`);
}
//(else, the method probably accessed other methods of the shape that DO use linkedProperty decorators, thus adding more traced propertyShapes. This is fine and works as intended)
return result;
};
}
//bind this descriptor to the class that defines it
//and bind the required arguments (which we know only now, but we need to know them when the descriptor runs, hence we bind them)
//overwrite the get method
Object.defineProperty(detectionClass.prototype, key, newDescriptor);
}
}
}
finger = Object.getPrototypeOf(finger);
}
//really we return a TraceShape, but it extends the given Shape class, so we need typescript to recognise it as such
//not sure how to do that dynamically
return traceShape;
}
exports.createTraceShape = createTraceShape;
class TestNode extends models_js_1.NamedNode {
constructor(property) {
let uri = models_js_1.NamedNode.createNewTempUri();
super(uri, true);
this.property = property;
}
getValue() {
let label = '';
if (this.property) {
if (this.property.hasProperty(rdfs_js_1.rdfs.label)) {
label = this.property.getValue(rdfs_js_1.rdfs.label);
}
else {
label = this.property.uri.split(/[\/#]/).pop();
}
}
return label;
}
hasProperty(property) {
return true;
}
getAll(property) {
return new NodeSet_js_1.NodeSet([this.getOne(property)]);
}
getOne(property) {
if (!super.hasProperty(property)) {
//test nodes AUTOMATICALLY generate a dummy test-node value when a property is requested
//however they avoid sending events about this
new models_js_1.Quad(this, property, new TestNode(property), undefined, false, false);
}
return super.getOne(property);
}
}
exports.TestNode = TestNode;
//# sourceMappingURL=TraceShape.js.map