UNPKG

lincd

Version:

LINCD is a JavaScript library for building user interfaces with linked data (also known as 'structured data', or RDF)

838 lines (837 loc) 37 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Shape = void 0; /* * 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 next_tick_1 = __importDefault(require("next-tick")); const models_js_1 = require("../models.js"); const rdf_js_1 = require("../ontologies/rdf.js"); const NodeValuesSet_js_1 = require("../collections/NodeValuesSet.js"); const rdfs_js_1 = require("../ontologies/rdfs.js"); const NodeSet_js_1 = require("../collections/NodeSet.js"); const Find_js_1 = require("../utils/Find.js"); const ShapeSet_js_1 = require("../collections/ShapeSet.js"); const CoreSet_js_1 = require("../collections/CoreSet.js"); const ShapeValuesSet_js_1 = require("../collections/ShapeValuesSet.js"); const ShapeClass_js_1 = require("../utils/ShapeClass.js"); const SelectQuery_js_1 = require("../queries/SelectQuery.js"); const TraceShape_js_1 = require("../utils/TraceShape.js"); /** * The base class of all classes that represent a rdfs:Class in the graph. * * This class helps form a bridge between the graph (RDF) world & the Object-Oriented typescript world. * Each Shape class has a static type property pointing to the rdfs:Class that it represents. * Each instance of a class that extends this Shape class points to a single node (NamedNode or Literal), that MUST have this rdfs:Class as its rdf:type in the graph. * * Classes that extend this class can thereby help simplify interactions with nodes that have a certain rdf:type by replacing low level property access (NamedNode.getAll(), getOne() etc) with high level methods that do not require knowledge of the underlying graph structure. * * @example * An Example: * ```tsx * @linkedShape * class Person extends Shape { * static type = foaf.Person * get friends() { * return this.getAll(foaf.hasFriend) * } * } * * let personNode = NamedNode.getOrCreate(); * personNode.set(rdf.type,foaf.Person); * * //creates an instance of the class Person, which points to (represents) personResource. * let person = new Person(personNode); * * //will log all the friends of the personResource (currently none) * console.log(person.friends); * ``` */ class Shape { /** * Creates a new instance of this class. * If no node is given, a new NamedNode will be generated and it's rdf:type will be set. * Only use this constructor directly if you want to create a new node as well. * If you want to create an instance of an existing node, use `node.getAs(Class)` or `Class.getOf(node)` * @param node */ constructor(node) { this.setupNode(node); } /** * Returns the node this instance represents. * * Since each node in RDF can have multiple types, each node can have multiple instances (multiple representations of itself reflecting the different things it 'is') * But each instance always only represents a single node */ get node() { //Instances of rdfs:Literal overwrite this method to return literalResource instead return this._node; } /** * returns the rdf:Class that this type of instance represents. */ get nodeShape() { return this.constructor.shape; // if (this.constructor['targetClass']) // { // return this.constructor['targetClass']; // } // throw new Error('The constructor of this instance has not defined a static targetClass.'); } /** * Returns the NamedNode that this instance represents. * * Since each node in RDF can have multiple types, each node can have multiple instances (multiple representations of itself reflecting the different things it 'is') * But each instance always only represents a single node * * NOTE: the node of an instance is NOT GUARANTEED to be a NamedNode. There are also instance of Literals. * Therefore only use this method if you are certain that the instance you have represents a NamedNode. * In that case this method - which works exactly the same as `.node` - simply tells the compiler that the return node is certainly a NamedNode. */ get namedNode() { //Instances of rdfs:Literal will return null so we can just return the node as is here, and use this method for type casting return this._node; } get value() { return this._node.value; } get uri() { return this._node.value; } //TODO: move to rdfs:Resource or owl:Thing shape? (and decide which one of those we want to promote) get label() { return this.getValue(rdfs_js_1.rdfs.label); } set label(val) { this.overwrite(rdfs_js_1.rdfs.label, new models_js_1.Literal(val)); } static create(updateObjectOrFn) { return this.queryParser.createQuery(updateObjectOrFn, this); } static delete(id) { return this.queryParser.deleteQuery(id, this); } /** * @internal * @param shapeClass * @param type */ static registerByType(shapeClass, type) { if (!type) { if (shapeClass === Shape) { return; } //TODO: add support for sh:targetNode, sh:targetObjectsOf and sh:targetSubjectsOf. Those would be fine as alternatives to targetClass (and the latter 2 define a PropertyShape) //warn developers against a common mistake: if no static shape is set by the Component it will inherit the one of the class it extends if (!shapeClass.hasOwnProperty('targetClass')) { console.warn(`Shape ${shapeClass.name} is not linked to a targetClass. Please define 'static targetClass:NamedNode'`); return; } type = shapeClass.targetClass; } //save in a map for finding the Shape back based on the type if (!this.typesToShapes.has(type)) { this.typesToShapes.set(type, new CoreSet_js_1.CoreSet()); } this.typesToShapes.get(type).add(shapeClass); } /** * Get a the matching shape classes that have a targetClass equal to the given type node * @internal * @param type * @param allowSuperClass */ static getClassesForType(type, allowSuperClass = false) { let instanceClasses = this.typesToShapes.get(type); if (allowSuperClass) { let subClasses = type.getDeep(rdfs_js_1.rdfs.subClassOf); // subClasses = Order.typesByDepth(subClasses); subClasses.delete(type); //<-- only delete after ordering, as it will be a new set and not the original PropertySet subClasses.forEach((subViewType) => { if (this.typesToShapes.has(subViewType)) { instanceClasses = instanceClasses.concat(this.typesToShapes.get(subViewType)); } }); } return instanceClasses; } static isValidNode(node) { this.ensureLinkedShape(); return this.shape.validateNode(node); } static query(subject, queryFn) { const _queryFn = subject && queryFn ? queryFn : subject; let _subject = queryFn ? subject : undefined; if (_subject instanceof SelectQuery_js_1.QueryShape) { _subject = { id: _subject.id }; } const query = new SelectQuery_js_1.SelectQueryFactory(this, _queryFn, _subject); return query; } static select(targetOrSelectFn, selectFn) { let _selectFn; let subject; if (selectFn) { _selectFn = selectFn; subject = targetOrSelectFn; } else { _selectFn = targetOrSelectFn; } const query = new SelectQuery_js_1.SelectQueryFactory(this, _selectFn, subject); let p = new Promise((resolve, reject) => { (0, next_tick_1.default)(() => { this.queryParser .selectQuery(query) .then((result) => { resolve(result); }) .catch((err) => { reject(err); }); }); }); return query.patchResultPromise(p); // return this.queryParser.query<ResultType>(query); } static update(id, updateObjectOrFn) { return this.queryParser.updateQuery(id, updateObjectOrFn, this); } static mapPropertyShapes(mapFunction) { let dummyNode = new TraceShape_js_1.TestNode(); let dummyShape = new this(dummyNode); //store the proxy on the shape, so we can access it later dummyShape.proxy = new Proxy(dummyShape, { get(target, key, receiver) { //if the key is a string if (typeof key === 'string') { //if this is a get method that is implemented by the QueryShape, then use that if (key in dummyShape) { //if it's a function, then bind it to the queryShape and return it so it can be called if (typeof dummyShape[key] === 'function') { return target[key].bind(target); } //if not, then a method/accessor of the original shape was called //then check if we have indexed any property shapes with that name for this shapes NodeShape let propertyShape = (0, ShapeClass_js_1.getPropertyShapeByLabel)(dummyShape.constructor, key.toString()); if (propertyShape) { //this method does not allow any further chaining, so we return the value of the property return propertyShape; } //otherwise return the value of the property on the original shape throw new Error(`${this.name}.${key.toString()} is missing a @linkedProperty decorator. This method can only access decorated get/set methods.`); } } }, }); //call the provided method with the proxy. When the method requests get/set methods, it will get the property shapes instead return mapFunction(dummyShape.proxy); } static isInstanceOfTargetClass(node) { return node.has(rdf_js_1.rdf.type, this.targetClass); } static getInstanceByType(node, ...shapes) { let matchingShape = shapes.find((shape) => { return node.has(rdf_js_1.rdf.type, shape.targetClass); }); if (matchingShape) { return matchingShape.getOf(node); } } /** * Searches instances with the given properties only from the local graph * @param properties * @param sanitized */ static searchLocal(properties, sanitized = false) { let quads = Find_js_1.Find.byPropertyValues(properties, this.targetClass, true, true, sanitized); let set = new ShapeSet_js_1.ShapeSet(); for (var node of quads.getSubjects()) { set.add(new this(node)); } return set; } /** * Searches instances with given properties * And if results are returned, it returns an instance of the first result, else null * @param properties */ static findLocal(properties, sanitized = false) { let results = this.searchLocal(properties, sanitized); if (results.size > 0) { return results.first(); } } /** * Finds all the instances whos rdf:type matches the targetClass of this shape * Ignores if the nodes are valid instances of the shape * Returns a set of shape instances. * This is helpful when using partly loaded data * @deprecated */ static getLocalInstancesByType() { return this.getSetOf(this.getLocalInstanceNodesByType()); } /** * Finds all the instances whos rdf:type matches the targetClass of this shape * Ignores if the nodes are valid instances of the shape * Returns a set of shape instances. * This is helpful when using partly loaded data * @deprecated */ static getLocalInstanceNodesByType() { //get all instances of the target class of this shape let nodes = this.targetClass.getAllInverse(rdf_js_1.rdf.type); //also look for shapes that extend this shape (0, ShapeClass_js_1.getSubShapesClasses)(this).forEach((shapeClass) => { //and add instances of those classes as well if (shapeClass.targetClass) { return shapeClass.targetClass .getAllInverse(rdf_js_1.rdf.type) .forEach((node) => { nodes.add(node); }); } }); return nodes; } /** * @deprecated * @param explicitInstancesOnly */ static getLocalInstances(explicitInstancesOnly = false) { //'this' is listed as a parameter ti be able to return a set of instances with the type of the actual class that extends Shape // https://www.typescriptlang.org/docs/handbook/generics.html#using-class-types-in-generics // https://stackoverflow.com/questions/34098023/typescript-self-referencing-return-type-for-static-methods-in-inheriting-classe?rq=1 return this.getSetOf(this.getLocalInstanceNodes()); } //TODO: to find Shape instances we need to not just check type, but all the constraints of this shape class /** * @deprecated */ static getNumLocalInstances() { return this.getLocalInstanceNodes().size; } /** * @deprecated * @param explicitInstancesOnly */ static getLocalInstanceNodes(explicitInstancesOnly = false) { let instanceNodes = new NodeSet_js_1.NodeSet(); //by default, look for instances of this shape class and all classes that extend it let targetClasses = [this].concat((0, ShapeClass_js_1.getSubShapesClasses)(this)); targetClasses.forEach((shapeClass) => { if (!shapeClass.targetClass) { console.warn('Shape class ' + shapeClass.name + ' does not have a targetClass. Please define a static targetClass:NamedNode'); return; } let potentialInstances = new NodeSet_js_1.NodeSet(); if (explicitInstancesOnly) { potentialInstances = shapeClass.targetClass .getInverseQuads(rdf_js_1.rdf.type) .filter((quad) => !quad.implicit) .getSubjects(); } else { potentialInstances = shapeClass.targetClass.getAllInverse(rdf_js_1.rdf.type); } //return only those instance nodes that are actual valid instances of this shape instanceNodes = instanceNodes.concat(potentialInstances.filter((node) => shapeClass.isValidNode(node))); }); return instanceNodes; } /** * use new Shape(node) instead, where Shape can be any class that extends Shape * @deprecated * @param node */ static getOf(node) { return new this(node); } /** * Retrieves an existing node or creates a new (temporary) node and then sets the right rdf:type * Then uses that node to return an instance of the Shape that you call this method from * So it works just like NamedNode.getOrCreate() but creates an instance of the right shape straight away. * Note that if the URI did not yet exist, it creates a temporary node, and hence only once you SAVE that node or shape * Will it (and its properties) be stored in permanent storage. * * @param uri * @param isTemporaryNodeIfNew */ static getFromURI(uri, isTemporaryNodeIfNew = true) { let node = models_js_1.NamedNode.getNamedNode(uri); if (node) { return new this(node); } else { node = models_js_1.NamedNode.getOrCreate(uri, isTemporaryNodeIfNew); if (this.targetClass) { node.set(rdf_js_1.rdf.type, this.targetClass); } return new this(node); } return new this(models_js_1.NamedNode.getOrCreate(uri)); } /** * Generates a URI from the given prefixURI + optional unique parameters * Then returns an instance of this shape with that URI, either from an existing or new node * This method is intended to be extended by other shapes. * The base implementation in Shape.ts will generate a unique URI if no uniqueParams are given, so extending methods may use super.getFromParams() when no params are given * @param prefixURI * @param uniqueParams */ static getFromParams(prefixURI, ...uniqueParams) { let postfix; if (uniqueParams.length) { postfix = uniqueParams.join('/'); } else { //here we expect that we'll create a new node, so the counter will be increased when we actually create it postfix = models_js_1.NamedNode.getCounter() + 1; } let uri = prefixURI + this.name + '/' + postfix; return this.getFromURI(uri); } static getSetOf(nodes, allowSubShapes = false) { if (!nodes) { throw new Error('No nodes provided to create shape instances of'); } if (nodes instanceof NodeValuesSet_js_1.NodeValuesSet && nodes.subject instanceof models_js_1.NamedNode) { return new ShapeValuesSet_js_1.ShapeValuesSet(nodes.subject, nodes.property, this, allowSubShapes); } return new ShapeSet_js_1.ShapeSet(nodes.map((node) => { return allowSubShapes ? (0, ShapeClass_js_1.getShapeOrSubShape)(node, this) : new this(node); })); } static ensureLinkedShape() { if (!this.shape) { console.warn(this.name + ' is not a linked shape. Did you forget to use the @linkedShape decorator?'); } } /** * Get all values of a certain property as instances of a certain shape. * The returned set of shape will automatically update when the property values change in the graph. * @param property * @param shapeClass */ getAllAs(property, shapeClass, allowSubShapes = false) { return new ShapeValuesSet_js_1.ShapeValuesSet(this.namedNode, property, shapeClass, allowSubShapes); // return (shapeClass as any).getSetOf(this.getAll(property),allowSubShapes); } /** * If a value exists for the given property, this returns that value as an instance of the given shape * If not, returns null * @param property * @param shape */ getOneAs(property, shape, allowSubShapes = false) { if (this.hasProperty(property)) { const value = this.getOne(property); if (allowSubShapes) { shape = (shape ? (0, ShapeClass_js_1.getMostSpecificShapesByType)(value, shape)[0] || shape : (0, ShapeClass_js_1.getMostSpecificShapesByType)(value)[0]) || Shape; } return new shape(value); } // return this.hasProperty(property) ? new (shape as any)(this.getOne(property)) as S : null; } equals(other, checkShapeType = false) { return (other instanceof Shape && other.node === this.node && (!checkShapeType || Object.getPrototypeOf(other) === Object.getPrototypeOf(this))); } /** * Makes sure that the node that this instance represents has the right rdf.type * Also makes sure that this instance is destructed if the node is removed * @internal * @param node */ setupNode(node) { if (node) { if (!(node instanceof models_js_1.Node)) { console.error('Invalid argument to constructor of shape:', node); throw new Error('Invalid argument provided to constructor of shape. Please provide an instance of a node.'); } this._node = node; } else { //this code gets triggered when you call new SomeShapeClass() without providing a node //some classes prefer a certain term type. E.g. RdfsLiteral will create a Literal node, and NodeShape will create a BlankNode //TODO: also look at inheritance chain, so that a class without preferredNodeKind that extends a class with preferredTermType still gets that inherited termType let termType = this.constructor['nodeKind'] || this.constructor['preferredNodeKind'] || models_js_1.NamedNode; //create a new temporary node, a Literal, NamedNode or BlankNode this._node = termType.create(true); let nodeShape = this.nodeShape; if (nodeShape && nodeShape.targetClass) { this._node.set(rdf_js_1.rdf.type, nodeShape.targetClass); } } //@TODO: do this for RdfsLiteral as well if they implement events at some point? // if (this._node instanceof NamedNode) { // this._node.on(NamedNode.NODE_REMOVED, this.destruct.bind(this)); // } } /** * Destructs the instance. Removes event listeners etc. Overwrite in each subclass of this class that uses custom event listeners */ destruct() { if (this._node instanceof models_js_1.NamedNode) { this._node.removeAllListeners(); } } validate() { var _a; return ((_a = this.nodeShape) === null || _a === void 0 ? void 0 : _a.validateNode(this.node)) || false; } getOne(property) { return this._node.getOne(property); } getAll(property) { return this._node.getAll(property); } getAllExplicit(property) { return this._node.getAllExplicit(property); } getOneFromPath(...properties) { return this.node.getOneFromPath(...properties); } getAllFromPath(...properties) { return this.node.getAllFromPath(...properties); } getOneInverse(property) { return this._node.getOneInverse(property); } getAllInverse(property) { return this._node.getAllInverse(property); } set(property, value) { return this._node.set(property, value); } setValue(property, value) { return this._node.setValue(property, value); } mset(property, values) { return this._node.mset(property, values); } overwrite(property, value) { return this._node.overwrite(property, value); } moverwrite(property, values) { return this._node.moverwrite(property, values); } remove() { return this.namedNode.remove(); } /** * @deprecated */ save() { return this.namedNode.save(); } unset(property, value) { return this._node.unset(property, value); } unsetAll(property) { return this._node.unsetAll(property); } has(property, value) { return this._node.has(property, value); } hasValue(property, value) { return this._node.hasValue(property, value); } hasExplicit(property, value) { return this._node.hasExplicit(property, value); } hasPath(properties) { return this._node.hasPath(properties); } hasPathTo(properties, endPoint) { return this._node.hasPathTo(properties, endPoint); } hasPathToSomeInSet(properties, endPoints) { return this._node.hasPathToSomeInSet(properties, endPoints); } /** * Checks if the node has a value for this property that is the exact same object as the given value * (as opposed to has() which also returns true for equivalent literal values in Literal objects) * @param property * @param value * @returns {boolean} */ hasExact(property, value = null) { return this._node.hasExact(property, value); } hasProperty(property) { return this._node.hasProperty(property); } hasInverse(property, value = null) { return this._node.hasInverse(property, value); } hasInverseProperty(property) { return this._node.hasInverseProperty(property); } getValue(property, language = '') { return this._node.getValue(property, language); } getProperties(includeFromIncomingArcs = false) { return this._node.getProperties(includeFromIncomingArcs); } getInverseProperties() { return this._node.getInverseProperties(); } getMultiple(properties) { return this._node.getMultiple(properties); } getMultipleInverse(properties) { return this._node.getMultipleInverse(properties); } getDeep(property, maxDepth) { return this._node.getDeep(property, maxDepth); } getQuads(property, value) { return this._node.getQuads(property, value); } getInverseQuads(property) { return this._node.getInverseQuads(property); } getAllInverseQuads(includeImplicit) { return this._node.getAllInverseQuads(includeImplicit); } getAllQuads(includeAsObject = false, includeImplicit = false) { return this._node.getAllQuads(includeAsObject, includeImplicit); } /** * Returns all quads related to this shape. * Overwrite this method to automatically send over quads to the frontend when this shape is sent over * This method is used internally by JSONWriter when sending a shape between environments by converting it to JSON & JSON-LD * @param includeImplicit */ getDataQuads(includeImplicit = false) { return this._node.getAllQuads(includeImplicit); } /** * Fires the given call back when ANY property of this node changes. * @param callback the method to be called when the change happens. The quads that have changed + the property that was updated are supplied as parameters * @param context give a context to make sure you can easily unset / clear event listeners. Usually you would provide 'this' as context */ onChangeAny(callback, context) { var _a; (_a = this.namedNode) === null || _a === void 0 ? void 0 : _a.onChangeAny(callback, context); } /** * Fires the given call back when this node become the value or is no longer the value of another node * @param callback the method to be called when the change happens. The quads that have changed + the property that was updated are supplied as parameters * @param context give a context to make sure you can easily unset / clear event listeners. Usually you would provide 'this' as context */ onChangeAnyInverse(callback, context) { var _a; (_a = this.namedNode) === null || _a === void 0 ? void 0 : _a.onChangeAnyInverse(callback, context); } /** * Fires the given call back when this node changes the values of the given property * @param callback the method to be called when the change happens. The quads that have changed + the property that was updated are supplied as parameters * @param context give a context to make sure you can easily unset / clear event listeners. Usually you would provide 'this' as context */ onChange(property, callback, context) { var _a; (_a = this.namedNode) === null || _a === void 0 ? void 0 : _a.onChange(property, callback, context); } /** * Fires the given callback when this node become the value or is no longer the value of the given property of another node * Example: if someGroup hasParticipant thisResource, and the group removes this node from its participants, it will trigger onChangeInverse for this node * @param callback the method to be called when the change happens. The quads that have changed + the property that was updated are supplied as parameters * @param context give a context to make sure you can easily unset / clear event listeners. Usually you would provide 'this' as context */ onChangeInverse(property, callback, context) { var _a; (_a = this.namedNode) === null || _a === void 0 ? void 0 : _a.onChangeInverse(property, callback, context); } /** * Call this when you want to stop listening for onChangeAny events. Make sure to provide the exact same BOUND instance of a method to properly clear the listener. OR make sure to provide a context both when setting and clearing the listener. * @param callback the exact same method you supplied to onChangeAny * @param context the same context you supplied to onChangeAny */ removeOnChangeAny(callback, context) { var _a; (_a = this.namedNode) === null || _a === void 0 ? void 0 : _a.removeOnChangeAny(callback, context); } /** * Call this when you want to stop listening for onChangeAnyInverse events. Make sure to provide the exact same BOUND instance of a method to properly clear the listener. OR make sure to provide a context both when setting and clearing the listener. * @param callback the exact same method you supplied to onChangeAnyInverse * @param context the same context you supplied to onChangeAnyInverse */ removeOnChangeAnyInverse(callback, context) { var _a; (_a = this.namedNode) === null || _a === void 0 ? void 0 : _a.removeOnChangeAnyInverse(callback, context); } /** * Call this when you want to stop listening for onChange events. Make sure to provide the exact same BOUND instance of a method as callback to properly clear the listener. OR make sure to provide a context both when setting and clearing the listener. * @param callback the exact same method you supplied to onChange * @param context the same context you supplied to onChange */ removeOnChange(property, callback, context) { var _a; (_a = this.namedNode) === null || _a === void 0 ? void 0 : _a.removeOnChange(property, callback, context); } /** * Call this when you want to stop listening for onChangeInverse events. Make sure to provide the exact same BOUND instance of a method as callback to properly clear the listener. OR make sure to provide a context both when setting and clearing the listener. * @param callback the exact same method you supplied to onChangeInverse * @param context the same context you supplied to onChangeInverse */ removeOnChangeInverse(property, callback, context) { var _a; (_a = this.namedNode) === null || _a === void 0 ? void 0 : _a.removeOnChangeInverse(property, callback, context); } /** * Call this when you want to stop listening for onChangeAny events. Other then removeOnChangeAny you only have to supply the context. * Use this if you no longer have access to the same bound listener function or you're otherwise unable to clear with removeOnChangeAny * @param context the same context you supplied to onChangeAny */ clearOnChangeAny(context) { var _a; (_a = this.namedNode) === null || _a === void 0 ? void 0 : _a.clearOnChangeAny(context); } /** * Call this when you want to stop listening for onChangeAnyInverse events. Other then removeOnChangeAnyInverse you only have to supply the context. * Use this if you no longer have access to the same bound listener function or you're otherwise unable to clear with removeOnChangeAnyInverse * @param context the same context you supplied to onChangeAnyInverse */ clearOnChangeAnyInverse(context) { var _a; (_a = this.namedNode) === null || _a === void 0 ? void 0 : _a.clearOnChangeAnyInverse(context); } /** * Call this when you want to stop listening for onChange events. Other then removeOnChange you only have to supply the context. * Use this if you no longer have access to the same bound listener function or you're otherwise unable to clear with removeOnChange * @param context the same context you supplied to onChange */ clearOnChange(property, context) { var _a; (_a = this.namedNode) === null || _a === void 0 ? void 0 : _a.clearOnChange(property, context); } /** * Call this when you want to stop listening for onChangeInverse events. Other then removeOnChangeInverse you only have to supply the context. * Use this if you no longer have access to the same bound listener function or you're otherwise unable to clear with removeOnChangeInverse * @param context the same context you supplied to onChangeAny */ clearOnChangeInverse(property, context) { var _a; (_a = this.namedNode) === null || _a === void 0 ? void 0 : _a.clearOnChangeInverse(property, context); } /** * Call this when you want to stop listening for onPredicateChange events * @param context the same context you supplied to onPredicateChange */ clearOnPredicateChange(context) { var _a; (_a = this.namedNode) === null || _a === void 0 ? void 0 : _a.clearOnPredicateChange(context); } /** * Returns true if this instance has the given type as the value of rdf.type * Syntactic sugar for this.has(rdf.type,type) * @param type */ isa(type) { return this.has(rdf_js_1.rdf.type, type); } /** * Other than NamedNode.promiseLoaded, a Shape will preload whatever data it requires to fulfill the constraints of the shape * NOTE: loading is handled by the current StorageController, by default there is no StorageController * @param {boolean} loadInverseProperties * @returns {Promise<boolean>} */ promiseLoaded(loadInverseProperties = false) { if (!this.loadPromise) { let promise = this.load(loadInverseProperties); this.loadPromise = { done: false, promise: promise, }; promise.then((res) => { this.loadPromise.done = true; return res; }); } return this.loadPromise.promise; } /** * Returns true if this instance has had its promiseLoaded function called and the loading has completed * NOTE: will return false if the instance has never loaded, regardless of whether the namedNode it represents is already loaded, and even if this instance would not load anything else */ isLoaded(includingInverseProperties = false) { return this.node instanceof models_js_1.NamedNode ? this.namedNode.isLoaded(includingInverseProperties) : true; } reload() { this.loadPromise = null; return this.promiseLoaded(); } load(loadInverseProperties = false) { if (!this.namedNode) return Promise.resolve(true); //load the node itself return this.namedNode.promiseLoaded(loadInverseProperties).then(() => { //make sure the reasoner has run on the loaded properties // return Reasoning.promiseComplete(); return null; }); } toString() { return '[' + this.node + ' as ' + this.constructor.name + ']'; } print(includeIncomingProperties = true) { // return Debug.print(this.node,includeIncomingProperties); return `${this.constructor.name} of ${this.node.print()}`; // typeof (typeof window !== 'undefined' ? window['dprint'] : global.dprint)(this, includeIncomingProperties); } /** * Returns a new cloned instance with the exact same quads * The instance only exists locally (as it's not yet saved) * @returns {T} */ clone() { let constructor = this.constructor; return new constructor(this.node.clone()); } } exports.Shape = Shape; /** * Points to the rdfs:Class that this typescript class represents. Each class extending Shape MUST define this explicitly. The appointed NamedNode value must be a rdfs:Class ([value] rdf:type rdfs:Class in the graph) @example An example Shape class that states that all matching nodes must have `rdf:type foaf:Person`. ```tsx import {foaf} from "./ontologies/foaf"; @linkedShape export class Person extends Shape { static targetClass:NamedNode = foaf.Person; } ``` */ Shape.targetClass = null; /** * Tracks which types (named nodes) map to which Shapes * @internal */ Shape.typesToShapes = new Map(); // static shapeCallbacks: ((shape) => void)[] = []; Shape.instancesLoaded = new Map(); //# sourceMappingURL=Shape.js.map