webgme-engine
Version:
WebGME server and Client API without a GUI
1,194 lines (1,048 loc) • 222 kB
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Source: common/core/core.js</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Source: common/core/core.js</h1>
<section>
<article>
<pre class="prettyprint source linenums"><code>/*globals define*/
/*eslint-env node, browser*/
/**
* This class defines the public API of the WebGME-Core
*
* @author kecso / https://github.com/kecso
* @module Core
*/
/**
* @typedef {object} Node - the object that represents the atomic element of the containment hierarchy.
*/
/**
* @typedef {object} DataObject - Inner data of {@link module:Core~Node} that can be serialized
* and saved in the storage.
*/
/**
* @typedef {object} GmePersisted - the result object of a persist which contains information about the newly
* created data objects.
* @prop {module:Core~ObjectHash} rootHash - Hash of the root node.
* @prop {object.<module:Core~ObjectHash, module:Core~DataObject>} objects - Hash of the root node.
*/
/**
* @typedef {string} ObjectHash - Unique SHA-1 hash for the node object.
* @example
* '#5496cf226542fcceccf89056f0d27564abc88c99'
*/
/**
* @typedef {string} GUID - Globally unique identifier. A formatted string containing hexadecimal characters. If some
* projects share some GUIDs that can only be because the node with the given identification represents the same
* concept.
* @example
* 'cd891e7b-e2ea-e929-f6cd-9faf4f1fc045'
*/
/**
* @typedef {object} Constraint - An object that represents some additional rule regarding some node of the project.
* @prop {string} script - The script which checks if the constraint is met.
* @prop {string} info - Short description of the constraint.
* @prop {string} priority - Gives instructions on how to deal with violations of the constraint.
*/
/**
* @typedef {object} DefinitionInfo - Contains the owner and the target of the meta-rule that makes the
* relationship between the given node and related node a valid one. There can be multiple meta-rules that make
* the relationship valid, but this is the first one that answers the question isValidChildOf, isValidTargetOf etc.
* @prop {Core~Node} ownerNode - The meta-node where the meta-rule is stored.
* @prop {Core~Node} targetNode - The meta-node the meta-rule is targeting.
*/
/**
* @typedef {object} RelationRule - An object that represents a relational type rule-set (pointer/set).
* @prop {integer} [min] - The minimum amount of target necessary for the relationship (if not present or '-1'
* then there is no minimum rule that applies)
* @prop {integer} [max] - The minimum amount of target necessary for the relationship (if not present or '-1'
* then there is no minimum rule that applies)
* @prop {object} [absolutePathOfTarget] - special rules regarding the given type (if the object is empty, it still
* represents that the type is a valid target of the relationship)
* @prop {integer} [absolutePathOfTarget.min] - The minimum amount of target necessary for the relationship
* from the given type (if not present or '-1' then there is no minimum rule that applies)
* @prop {integer} [absolutePathOfTarget.max] - The minimum amount of target necessary for the relationship
* from the given type (if not present or '-1' then there is no minimum rule that applies)
* @example
* '{
* 'min': 1,
* 'max': -1,
* 'any/path/of/node':{
* 'min':-1,
* 'max':2
* },
* 'any/other/valid/path':{
* }
* }'
*/
/**
* @typedef {object} MixinViolation - An object that has information about a mixin violation in the given node.
* @prop {string} [severity] - The severity of the given error ('error','warning').
* @prop {string} [type] - 'missing', 'attribute collision', 'set collision',
* 'pointer collision', 'containment collision', 'aspect collision', 'constraint collision'
* @prop {string|undefined} [ruleName] - The name of the affected rule definition (if available).
* @prop {string|undefined} [targetInfo] - The path of the target of the violation (if available).
* @prop {module:Core~Node|undefined} [targetNode] - The target node of the violation (if available).
* @prop {string[]} [collisionPaths] - The list of paths of colliding nodes (if any).
* @prop {module:Core~Node[]} [collisionNodes] - The colliding mixin nodes (if any).
* @prop {string} [message] - The description of the violation.
* @prop {string} [hint] - Hint on how to resolve the issue.
* @example
* '{
* 'severity': 'error',
* 'type': 'missing',
* 'targetInfo': '/E/b',
* 'message': '[MyObject]: mixin node "E/b" is missing from the Meta',
* 'hint': 'Remove mixin or add to the Meta'
* }'
* @example
* '{
* 'severity': 'warning',
* 'type': 'attribute collision',
* 'ruleName': 'value',
* 'collisionPaths': ['/E/a','/E/Z'],
* 'collisionNodes': [Object,Object],
* 'message':'[MyObject]: inherits attribute definition "value" from [TypeA] and [TypeB]',
* 'hint': 'Remove one of the mixin relations'
* }'
*/
define([
'common/core/corerel',
'common/core/setcore',
'common/core/guidcore',
'common/core/nullpointercore',
'common/core/coreunwrap',
'common/core/coretype',
'common/core/constraintcore',
'common/core/coretree',
'common/core/metacore',
'common/core/coretreeloader',
'common/core/corediff',
'common/core/metacachecore',
'common/core/mixincore',
'common/core/metaquerycore',
'common/regexp',
'common/core/librarycore',
'common/core/CoreIllegalArgumentError',
'common/core/CoreIllegalOperationError',
'common/core/constants'
], function (CoreRel,
Set,
Guid,
NullPtr,
UnWrap,
Type,
Constraint,
CoreTree,
MetaCore,
TreeLoader,
CoreDiff,
MetaCacheCore,
MixinCore,
MetaQueryCore,
REGEXP,
LibraryCore,
CoreIllegalArgumentError,
CoreIllegalOperationError,
CONSTANTS) {
'use strict';
var isValidNode,
isValidPath;
function ensureType(input, nameOfInput, type, isAsync) {
var error;
if (typeof input !== type) {
error = new CoreIllegalArgumentError('Parameter \'' + nameOfInput + '\' is not of type ' + type + '.');
if (isAsync) {
return error;
} else {
throw error;
}
}
}
function ensureValue(input, nameOfInput, isAsync) {
var error;
if (input === undefined) {
error = new CoreIllegalArgumentError('Parameter \'' + nameOfInput + '\' cannot be undefined.');
if (isAsync) {
return error;
} else {
throw error;
}
}
}
function ensureInstanceOf(input, nameOfInput, type, isAsync) {
var error;
if (input instanceof type === false) {
error = new CoreIllegalArgumentError('Parameter \'' + nameOfInput + '\' is not of type ' + type + '.');
if (isAsync) {
return error;
} else {
throw error;
}
}
}
function ensurePath(input, nameOfInput, isAsync) {
var error;
if (isValidPath(input) === false) {
error = new CoreIllegalArgumentError('Parameter \'' + nameOfInput + '\' is not a valid path.');
if (isAsync) {
return error;
} else {
throw error;
}
}
}
function ensureNode(input, nameOfInput, isAsync) {
var error;
if (isValidNode(input) === false) {
error = new CoreIllegalArgumentError('Parameter \'' + nameOfInput + '\' is not a valid node.');
if (isAsync) {
return error;
} else {
throw error;
}
}
}
function ensureHash(input, nameOfInput, isAsync) {
var error;
if (REGEXP.DB_HASH.test(input) === false) {
error = new CoreIllegalArgumentError('Parameter \'' + nameOfInput + '\' is not a valid hash.');
if (isAsync) {
return error;
} else {
throw error;
}
}
}
function ensureGuid(input, nameOfInput, isAsync) {
var error;
if (REGEXP.GUID.test(input) === false) {
error = new CoreIllegalArgumentError('Parameter \'' + nameOfInput + '\' is not a valid GUID.');
if (isAsync) {
return error;
} else {
throw error;
}
}
}
function ensureMinMax(input, nameOfInput, isAsync) {
var error;
if (input === null || input === undefined) {
return;
}
if (typeof input === 'number' && Number.isSafeInteger(input) && input >= -1) {
return;
}
error = new CoreIllegalArgumentError('Parameter ' + nameOfInput + ' is not a safe integer from [-1,∞).');
if (error) {
if (isAsync) {
return error;
} else {
throw error;
}
}
}
function ensureRelationName(input, nameOfInput, isAsync) {
var error,
reserved = [
CONSTANTS.BASE_POINTER,
CONSTANTS.OVERLAYS_PROPERTY,
CONSTANTS.MEMBER_RELATION
];
if (typeof input !== 'string') {
error = new CoreIllegalArgumentError('Parameter ' + nameOfInput + ' is not of type string.');
} else {
if (input.indexOf('_') === 0 ||
reserved.indexOf(input) !== -1) {
error = new CoreIllegalArgumentError('Parameter ' + nameOfInput + ' cannot start with \'_\'' +
', or be equal with any of the reserved ' + reserved + ' words.');
}
}
if (error) {
if (isAsync) {
return error;
} else {
throw error;
}
}
}
function ensureMongoCompatibleKey(input, nameOfInput, hiddenIsFine, isAsync) {
var error = null,
realInput = input;
if (hiddenIsFine === true && input[0] === '_') {
realInput = input.substr(1);
}
if (REGEXP.DOCUMENT_KEY.test(realInput) === false) {
error = new CoreIllegalArgumentError('Parameter ' + nameOfInput +
' is not a valid key (cannot contain "." or "$"' +
(hiddenIsFine ? '' : ', or start with "_"') + ').');
}
if (error) {
if (isAsync) {
return error;
} else {
throw error;
}
}
}
function getCommonAncestor(node1, node2, getter) {
function getChain(node) {
var ancestors = [];
while (node) {
ancestors.push(node);
node = getter(node);
}
return ancestors;
}
var ancestors2 = getChain(node2),
i;
while (node1) {
for (i = 0; i < ancestors2.length; i += 1) {
if (node1 === ancestors2[i]) {
return node1;
}
}
node1 = getter(node1);
}
return null;
}
/**
* @param {ProjectInterface} project - project connected to storage
* @param {object} options - contains logging information
* @param {object} options.logger - gmeLogger
* @param {object} options.globConf - gmeConfig
* @alias Core
* @description The Core defines the main API for model manipulation and traversal. It is important to note, that
* all 'Path' function must be used with caution as the returned information is just an estimate and does not
* guarantee that the actual node will exist (as in certain scenarios they might become invalid and need to
* be removed, but said removal can only take place during their load). Try to always 'Load' every
* node before depending on their paths.
* @constructor
*/
function Core(project, options) {
var core,
coreLayers = [];
coreLayers.push(CoreRel);
coreLayers.push(NullPtr);
coreLayers.push(Type);
coreLayers.push(NullPtr);
coreLayers.push(Set);
coreLayers.push(Guid);
coreLayers.push(Constraint);
coreLayers.push(MetaCore);
coreLayers.push(MetaCacheCore);
coreLayers.push(MixinCore);
coreLayers.push(MetaQueryCore);
coreLayers.push(CoreDiff);
coreLayers.push(TreeLoader);
coreLayers.push(LibraryCore);
// TODO check how we should handle the TASYNC error handling...
// if (options.usertype !== 'tasync') {
// coreLayers.push(UnWrap);
// }
coreLayers.push(UnWrap);
core = coreLayers.reduce(function (inner, Class) {
return new Class(inner, options);
}, new CoreTree(project, options));
isValidNode = core.isValidNode;
isValidPath = core.isValidPath;
/**
* Returns the parent of the node.
* @param {module:Core~Node} node - the node in question
*
* @return {module:Core~Node|null} Returns the parent of the node or NULL if it has no parent.
*
* @throws {CoreIllegalArgumentError} If some of the parameters don't match the input criteria.
* @throws {CoreInternalError} If some internal error took place inside the core layers.
*/
this.getParent = function (node) {
ensureNode(node, 'node');
return core.getParent(node);
};
/**
* Returns the common parent node of all supplied nodes. Note that if a node and its parent are passed,
* the method will return the parent of the parent.
* @param {...module:Core~Node} nodes - a variable number of nodes to compare
*
* @return {module:Core~Node|null} The common parent. Will be null whenever the root-node is passed in.
* @example
* core.getCommonParent(node1, node2, node3);
* @throws {CoreIllegalArgumentError} If some of the parameters don't match the input criteria.
* @throws {CoreInternalError} If some internal error took place inside the core layers.
*/
this.getCommonParent = function () {
var nodesArr = (arguments.length === 1 ? [arguments[0]] : Array.apply(null, arguments)),
result,
i;
nodesArr.forEach(function (node, idx) {
ensureNode(node, 'arguments[' + idx + ']');
});
result = nodesArr[0];
for (i = 1; i < nodesArr.length; i += 1) {
result = getCommonAncestor(result, nodesArr[i], core.getParent);
}
if (result && nodesArr.indexOf(result) > -1) {
result = core.getParent(result);
}
return result || null;
};
/**
* Returns the parent-relative identifier of the node.
* @param {module:Core~Node} node - the node in question.
*
* @return {string|null} Returns the last segment of the node path.
*
* @throws {CoreIllegalArgumentError} If some of the parameters don't match the input criteria.
* @throws {CoreInternalError} If some internal error took place inside the core layers.
*/
this.getRelid = function (node) {
ensureNode(node, 'node');
return core.getRelid(node);
};
/**
* Returns the root node of the containment tree that node is part of.
* @param {module:Core~Node} node - the node in question.
*
* @return {module:Core~Node} Returns the root of the containment hierarchy (it can be the node itself).
*
* @throws {CoreIllegalArgumentError} If some of the parameters don't match the input criteria.
* @throws {CoreInternalError} If some internal error took place inside the core layers.
*/
this.getRoot = function (node) {
ensureNode(node, 'node');
return core.getRoot(node);
};
/**
* Returns the complete path of the node in the containment hierarchy.
* @param {module:Core~Node} node - the node in question.
*
* @return {string} Returns a path string where each portion is a relative id and they are separated by '/'.
* The path can be empty as well if the node in question is the root itself, otherwise it should be a chain
* of relative ids from the root of the containment hierarchy.
*
* @throws {CoreIllegalArgumentError} If some of the parameters don't match the input criteria.
* @throws {CoreInternalError} If some internal error took place inside the core layers.
*/
this.getPath = function (node) {
ensureNode(node, 'node');
return core.getPath(node);
};
/**
* Retrieves the child of the input node at the given relative id. It is not an asynchronous load
* and it automatically creates the child under the given relative id if no child was there beforehand.
* @param {module:Core~Node} node - the node in question.
* @param {string} relativeId - the relative id which our child in question has.
*
* @return {module:Core~Node} Return an empty node if it was created as a result of the function or
* return the already existing and loaded node if it found.
*
* @throws {CoreIllegalArgumentError} If some of the parameters don't match the input criteria.
* @throws {CoreInternalError} If some internal error took place inside the core layers.
*/
this.getChild = function (node, relativeId) {
ensureNode(node, 'node');
ensureType(relativeId, 'relativeId', 'string');
return core.getChild(node, relativeId);
};
/**
* Checks if the node in question has some actual data.
* @param {module:Core~Node} node - the node in question.
*
* @return {bool} Returns true if the node is 'empty' meaning that it is not reserved by real data.
* Returns false if the node is exists and have some meaningful value.
*
* @throws {CoreIllegalArgumentError} If some of the parameters don't match the input criteria.
* @throws {CoreInternalError} If some internal error took place inside the core layers.
*/
this.isEmpty = function (node) {
ensureNode(node, 'node');
return core.isEmpty(node);
};
/**
* Returns the calculated hash and database id of the data for the node.
* @param {module:Core~Node} node - the node in question.
*
* @return {module:Core~ObjectHash} Returns the hash value of the data for the given node.
* An empty string is returned when the node was mutated and not persisted.
*
* @throws {CoreIllegalArgumentError} If some of the parameters don't match the input criteria.
* @throws {CoreInternalError} If some internal error took place inside the core layers.
*/
this.getHash = function (node) {
ensureNode(node, 'node');
return core.getHash(node);
};
/**
* Persists the changes made in memory and computed the data blobs that needs to be saved into the database
* to make the change and allow other users to see the new state of the project.
* @param {module:Core~Node} node - some node element of the modified containment hierarchy (usually the root).
*
* @return {module:Core~GmePersisted} The function returns an object which collects all the changes
* on data level and necessary to update the database on server side. Keys of the returned object are 'rootHash'
* and 'objects'. The values of these should be passed to project.makeCommit.
*
* @throws {CoreIllegalArgumentError} If some of the parameters don't match the input criteria.
* @throws {CoreInternalError} If some internal error took place inside the core layers.
*/
this.persist = function (node) {
ensureNode(node, 'node');
return core.persist(node);
};
/**
* Loads the data object with the given hash and makes it a root of a containment hierarchy.
* @param {module:Core~ObjectHash} hash - the hash of the data object we like to load as root.
* @param {function} [callback]
* @param {Error|CoreIllegalArgumentError|CoreInternalError|null} callback.error - the result of the execution
* @param {module:Core~Node} callback.node - the resulting root node
*
* @return {external:Promise} If no callback is given, the result will be provided in
* a promiselike manner.
*
* @throws {CoreIllegalArgumentError} If some of the parameters don't match the input criteria.
*/
this.loadRoot = function (hash, callback) {
var error = null;
ensureType(callback, 'callback', 'function');
error = ensureHash(hash, 'hash', true);
if (error) {
callback(error);
} else {
core.loadRoot(hash, callback);
}
};
/**
* Loads the child of the given parent pointed by the relative id. Behind the scenes, it means
* that it actually loads the data pointed by a hash stored inside the parent under the given id
* and wraps it in a node object which will be connected to the parent as a child in the containment
* hierarchy. If there is no such relative id reserved, the call will return with null.
* @param {module:Core~Node} parent - the container node in question.
* @param {string} relativeId - the relative id of the child in question.
* @param {function} [callback]
* @param {Error|CoreIllegalArgumentError|CoreInternalError|null} callback.error - the result of the execution
* @param {module:Core~Node} callback.node - the resulting child
*
* @return {external:Promise} If no callback is given, the result will be provided in a promise.
*
* @throws {CoreIllegalArgumentError} If some of the parameters don't match the input criteria.
*/
this.loadChild = function (node, relativeId, callback) {
var error = null;
ensureType(callback, 'callback', 'function');
error = ensureNode(node, 'node', true);
error = error || ensureType(relativeId, 'relativeId', 'string', true);
if (error) {
callback(error);
} else {
core.loadChild(node, relativeId, callback);
}
};
/**
* From the given starting node, it loads the path given as a series of relative ids (separated by '/')
* and returns the node it finds at the ends of the path. If there is no node, the function will return null.
* @param {module:Core~Node} node - the starting node of our search.
* @param {string} relativePath - the relative path - built by relative ids - of the node in question.
* @param {function} [callback]
* @param {Error|CoreIllegalArgumentError|CoreInternalError|null} callback.error - the result of the execution
* @param {module:Core~Node} callback.node - the resulting node
*
* @return {external:Promise} If no callback is given, the result will be provided in a promise.
*
* @throws {CoreIllegalArgumentError} If some of the parameters don't match the input criteria.
*/
this.loadByPath = function (node, relativePath, callback) {
var error = null;
ensureType(callback, 'callback', 'function');
error = ensureNode(node, 'node', true);
error = error || ensurePath(relativePath, 'relativePath', true);
if (error) {
callback(error);
} else {
core.loadByPath(node, relativePath, callback);
}
};
/**
* Loads all the children of the given parent. As it first checks the already reserved relative ids of
* the parent, it only loads the already existing children (so no on-demand empty node creation).
* @param {module:Core~Node} node - the container node in question.
* @param {function} [callback]
* @param {Error|CoreIllegalArgumentError|CoreInternalError|null} callback.error - the result of the execution
* @param {module:Core~Node[]} callback.children - the resulting children
*
* @return {external:Promise} If no callback is given, the result will be provided in a promise.
*
* @throws {CoreIllegalArgumentError} If some of the parameters don't match the input criteria.
*/
this.loadChildren = function (node, callback) {
var error = null;
ensureType(callback, 'callback', 'function');
error = ensureNode(node, 'node', true);
if (error) {
callback(error);
} else {
core.loadChildren(node, callback);
}
};
/**
* Loads all the children of the given parent that has some data and not just inherited. As it first checks
* the already reserved relative ids of the parent, it only loads the already existing children
* (so no on-demand empty node creation).
* @param {module:Core~Node} node - the container node in question.
* @param {function} [callback]
* @param {Error|CoreIllegalArgumentError|CoreInternalError|null} callback.error - the result of the execution
* @param {module:Core~Node[]} callback.node - the resulting children
*
* @return {external:Promise} If no callback is given, the result will be provided in a promise.
*
* @throws {CoreIllegalArgumentError} If some of the parameters don't match the input criteria.
*/
this.loadOwnChildren = function (node, callback) {
var error = null;
ensureType(callback, 'callback', 'function');
error = ensureNode(node, 'node', true);
if (error) {
callback(error);
} else {
core.loadOwnChildren(node, callback);
}
};
/**
* Loads the target of the given pointer of the given node. In the callback the node can have three values:
* if the node is valid, then it is the defined target of a valid pointer,
* if the returned value is null, then it means that the pointer is defined, but has no real target,
* finally if the returned value is undefined than there is no such pointer defined for the given node.
* @param {module:Core~Node} node - the source node in question.
* @param {string} pointerName - the name of the pointer.
* @param {function} [callback]
* @param {Error|CoreIllegalArgumentError|CoreInternalError|null} callback.error - the result of the execution
* @param {module:Core~Node} callback.node - the resulting target
*
* @return {external:Promise} If no callback is given, the result will be provided in a promise.
*
* @throws {CoreIllegalArgumentError} If some of the parameters don't match the input criteria.
*/
this.loadPointer = function (node, pointerName, callback) {
var error = null;
ensureType(callback, 'callback', 'function');
error = ensureNode(node, 'node', true);
error = error || ensureType(pointerName, 'pointerName', 'string', true);
if (error) {
callback(error);
} else {
core.loadPointer(node, pointerName, callback);
}
};
/**
* Loads all the source nodes that has such a pointer and its target is the given node.
* @param {module:Core~Node} node - the target node in question.
* @param {string} pointerName - the name of the pointer of the sources.
* @param {function} [callback]
* @param {Error|CoreIllegalArgumentError|CoreInternalError|null} callback.error - the result of the execution
* @param {module:Core~Node[]} callback.node - the resulting sources
*
* @return {external:Promise} If no callback is given, the result will be provided in a promise.
*
* @throws {CoreIllegalArgumentError} If some of the parameters don't match the input criteria.
*/
this.loadCollection = function (node, pointerName, callback) {
var error = null;
ensureType(callback, 'callback', 'function');
error = ensureNode(node, 'node', true);
error = error || ensureType(pointerName, 'pointerName', 'string', true);
if (error) {
callback(error);
} else {
core.loadCollection(node, pointerName, callback);
}
};
/**
* Loads a complete sub-tree of the containment hierarchy starting from the given node.
* @param {module:Core~Node} node - the node that is the root of the sub-tree in question.
* @param {function} [callback]
* @param {Error|CoreIllegalArgumentError|CoreInternalError|null} callback.error - the result of the execution
* @param {module:Core~Node[]} callback.nodes - the resulting sources
*
* @return {external:Promise} If no callback is given, the result will be provided in a promise.
*
* @throws {CoreIllegalArgumentError} If some of the parameters don't match the input criteria.
*/
this.loadSubTree = function (node, callback) {
var error = null;
ensureType(callback, 'callback', 'function');
error = ensureNode(node, 'node', true);
if (error) {
callback(error);
} else {
core.loadSubTree(node, callback);
}
};
/**
* Loads a complete sub-tree of the containment hierarchy starting from the given node, but load only those
* children that has some additional data and not purely inherited.
* @param {module:Core~Node} node - the container node in question.
* @param {function} [callback]
* @param {Error|CoreIllegalArgumentError|CoreInternalError|null} callback.error - the result of the execution
* @param {module:Core~Node[]} callback.nodes - the resulting sources
*
* @return {external:Promise} If no callback is given, the result will be provided in a promise.
*
* @throws {CoreIllegalArgumentError} If some of the parameters don't match the input criteria.
*/
this.loadOwnSubTree = function (node, callback) {
var error = null;
ensureType(callback, 'callback', 'function');
error = ensureNode(node, 'node', true);
if (error) {
callback(error);
} else {
core.loadOwnSubTree(node, callback);
}
};
/**
* Loads a complete containment hierarchy using the data object - pointed by the given hash -
* as the root.
* @param {module:Core~ObjectHash} hash - hash of the root node.
* @param {function} [callback]
* @param {Error|CoreIllegalArgumentError|CoreInternalError|null} callback.error - the result of the execution.
* @param {module:Core~Node[]} callback.nodes - the resulting nodes.
*
* @return {external:Promise} If no callback is given, the result will be provided in a promise.
*
* @throws {CoreIllegalArgumentError} If some of the parameters don't match the input criteria.
*/
this.loadTree = function (hash, callback) {
var error = null;
ensureType(callback, 'callback', 'function');
error = ensureHash(hash, 'hash', true);
if (error) {
callback(error);
} else {
core.loadTree(hash, callback);
}
};
/**
* Collects the relative ids of all the children of the given node.
* @param {module:Core~Node} node - the container node in question.
*
* @return {string[]} The function returns an array of the relative ids.
*/
this.getChildrenRelids = function (node) {
ensureNode(node, 'node');
return core.getChildrenRelids(node);
};
/**
* Collects the relative ids of all the children of the given node that has some data and not just inherited.
* N.B. Do not mutate the returned array!
* @param {module:Core~Node} node - the container node in question.
*
* @return {string[]} The function returns an array of the relative ids.
*
* @throws {CoreIllegalArgumentError} If some of the parameters don't match the input criteria.
* @throws {CoreInternalError} If some internal error took place inside the core layers.
*/
this.getOwnChildrenRelids = function (node) {
ensureNode(node, 'node');
return core.getOwnChildrenRelids(node);
};
/**
* Collects the paths of all the children of the given node.
* @param {module:Core~Node} node - the container node in question.
*
*@return {string[]} The function returns an array of the absolute paths of the children.
*
* @throws {CoreIllegalArgumentError} If some of the parameters don't match the input criteria.
* @throws {CoreInternalError} If some internal error took place inside the core layers.
*/
this.getChildrenPaths = function (node) {
ensureNode(node, 'node');
return core.getChildrenPaths(node);
};
/**
* Collects the paths of all the children of the given node that has some data as well and not just inherited.
* @param {module:Core~Node} parent - the container node in question.
*
*@return {string[]} The function returns an array of the absolute paths of the children.
*
* @throws {CoreIllegalArgumentError} If some of the parameters don't match the input criteria.
* @throws {CoreInternalError} If some internal error took place inside the core layers.
*/
this.getOwnChildrenPaths = function (node) {
ensureNode(node, 'node');
return core.getOwnChildrenPaths(node);
};
/**
* Creates a node according to the given parameters.
* @param {object} [parameters] - the details of the creation.
* @param {module:Core~Node|null} [parameters.parent] - the parent of the node to be created.
* @param {module:Core~Node|null} [parameters.base] - the base of the node to be created.
* @param {string} [parameters.relid] - the relative id of the node to be created (if reserved, the function
* returns the node behind the relative id)
* @param {module:Core~GUID} [parameters.guid] - the GUID of the node to be created
*
*
* @return {module:Core~Node} The function returns the created node.
*
* @throws {CoreIllegalArgumentError} If some of the parameters don't match the input criteria.
* @throws {CoreIllegalOperationError} If the context of the operation is not allowed.
* @throws {CoreInternalError} If some internal error took place inside the core layers.
*/
this.createNode = function (parameters) {
if (parameters) {
ensureType(parameters, 'parameters', 'object');
if (Object.hasOwn(parameters, 'parent') &&
parameters.parent !== null && parameters.parent !== undefined) {
ensureNode(parameters.parent, 'parameters.parent');
}
if (Object.hasOwn(parameters, 'base') &&
parameters.base !== null && parameters.base !== undefined) {
ensureNode(parameters.base, 'parameters.base');
}
if (Object.hasOwn(parameters, 'guid') && parameters.guid !== undefined) {
ensureGuid(parameters.guid, 'parameters.guid');
}
}
return core.createNode(parameters);
};
/**
* Creates a child, with base as provided, inside the provided node.
* @param {module:Core~Node} node - the parent of the node to be created.
* @param {module:Core~Node} base - the base of the node to be created.
*
* @return {module:Core~Node} The function returns the created child node.
*
* @throws {CoreIllegalArgumentError} If some of the parameters don't match the input criteria.
* @throws {CoreIllegalOperationError} If the context of the operation is not allowed.
* @throws {CoreInternalError} If some internal error took place inside the core layers.
*/
this.createChild = function (node, base) {
ensureNode(node, 'node');
ensureNode(base, 'base');
return core.createNode({parent: node, base: base});
};
/**
* Removes a node from the containment hierarchy.
* @param {module:Core~Node} node - the node to be removed.
*
* @throws {CoreIllegalArgumentError} If some of the parameters don't match the input criteria.
* @throws {CoreIllegalOperationError} If the context of the operation is not allowed.
* @throws {CoreInternalError} If some internal error took place inside the core layers.
*/
this.deleteNode = function (node) {
ensureNode(node, 'node');
if (core.getParent(node) === null) {
throw new CoreIllegalOperationError('Not allowed to delete node without a parent.');
}
return core.deleteNode(node, false);
};
/**
* Copies the given node into parent.
* @param {module:Core~Node} node - the node to be copied.
* @param {module:Core~Node} parent - the parent node of the copy.
*
* @return {module:Core~Node} The function returns the copied node.
*
* @throws {CoreIllegalArgumentError} If some of the parameters don't match the input criteria.
* @throws {CoreIllegalOperationError} If the context of the operation is not allowed.
* @throws {CoreInternalError} If some internal error took place inside the core layers.
*/
this.copyNode = function (node, parent) {
ensureNode(node, 'node');
ensureNode(parent, 'parent');
return core.copyNode(node, parent);
};
/**
* Copies the given nodes into parent.
* @param {module:Core~Node[]} nodes - the nodes to be copied.
* @param {module:Core~Node} parent - the parent node of the copy.
*
* @return {module:Core~Node[]} The function returns an array of the copied nodes. The order follows
* the order of originals.
*
* @throws {CoreIllegalArgumentError} If some of the parameters don't match the input criteria.
* @throws {CoreIllegalOperationError} If the context of the operation is not allowed.
* @throws {CoreInternalError} If some internal error took place inside the core layers.
*/
this.copyNodes = function (nodes, parent) {
var i;
ensureInstanceOf(nodes, 'nodes', Array);
for (i = 0; i < nodes.length; i += 1) {
ensureNode(nodes[i], 'nodes[' + i + ']');
}
ensureNode(parent, 'parent');
return core.copyNodes(nodes, parent);
};
/**
* Checks if parent can be the new parent of node.
* @param {module:Core~Node} node - the node in question.
* @param {module:Core~Node} parent - the new parent.
*
* @return {boolean} True if the supplied parent is a valid parent for the node.
*
* @throws {CoreIllegalArgumentError} If some of the parameters don't match the input criteria.
* @throws {CoreInternalError} If some internal error took place inside the core layers.
*/
this.isValidNewParent = function (node, parent) {
ensureNode(node, 'node');
ensureNode(parent, 'parent');
return core.isValidNewParent(node, parent);
};
/**
* Moves the given node under the given parent.
* @param {module:Core~Node} node - the node to be moved.
* @param {module:Core~Node} parent - the parent node of the copy.
*
* @return {module:Core~Node} The function returns the node after the move.
*
* @throws {CoreIllegalArgumentError} If some of the parameters don't match the input criteria.
* @throws {CoreIllegalOperationError} If the context of the operation is not allowed.
* @throws {CoreInternalError} If some internal error took place inside the core layers.
*/
this.moveNode = function (node, parent) {
ensureNode(node, 'node');
ensureNode(parent, 'parent');
return core.moveNode(node, parent);
};
/**
* Returns the names of the defined attributes of the node.
* @param {module:Core~Node} node - the node in question.
*
* @return {string[]} The function returns an array of the names of the attributes of the node.
*
* @throws {CoreIllegalArgumentError} If some of the parameters don't match the input criteria.
* @throws {CoreInternalError} If some internal error took place inside the core layers.
*/
this.getAttributeNames = function (node) {
ensureNode(node, 'node');
return core.getAttributeNames(node);
};
/**
* Retrieves the value of the given attribute of the given node.
* @param {module:Core~Node} node - the node in question.
* @param {string} name - the name of the attribute.
*
* @return {string|number|bool|object|undefined} The function returns the value of the attribute of the node.
* If the value is undefined that means the node do not have
* such attribute defined.
*
* @throws {CoreIllegalArgumentError} If some of the parameters don't match the input criteria.
* @throws {CoreInternalError} If some internal error took place inside the core layers.
*/
this.getAttribute = function (node, name) {
ensureNode(node, 'node');
ensureType(name, 'name', 'string');
return core.copyIfObject(core.getAttribute(node, name));
};
/**
* Sets the value of the given attribute of the given node. It defines the attribute on demand, means that it
* will set the given attribute even if was ot defined for the node beforehand.
* @param {module:Core~Node} node - the node in question.
* @param {string} name - the name of the attribute.
* @param {string|number|bool|object} value - the new of the attribute, undefined is not allowed.
*
* @throws {CoreIllegalArgumentError} If some of the parameters don't match the input criteria.
* @throws {CoreIllegalOperationError} If the context of the operation is not allowed.
* @throws {CoreInternalError} If some internal error took place inside the core layers.
*/
this.setAttribute = function (node, name, value) {
ensureNode(node, 'node');
ensureType(name, 'name', 'string');
ensureMongoCompatibleKey(name, 'name', true);
ensureValue(value, 'value');
return core.setAttribute(node, name, value);
};
/**
* Removes the given attributes from the given node.
* @param {module:Core~Node} node - the node in question.
* @param {string} name - the name of the attribute.
*
* @throws {CoreIllegalArgumentError} If some of the parameters don't match the input criteria.
* @throws {CoreIllegalOperationError} If the context of the operation is not allowed.
* @throws {CoreInternalError} If some internal error took place inside the core layers.
*/
this.delAttribute = function (node, name) {
ensureNode(node, 'node');
ensureType(name, 'name', 'string');
return core.delAttribute(node, name);
};
/**
* Returns the names of the defined registry entries of the node.
* @param {module:Core~Node} node - the node in question.
*
* @return {string[]} The function returns an array of the names of the registry entries of the node.
*
* @throws {CoreIllegalArgumentError} If some of the parameters don't match the input criteria.
* @throws {CoreInternalError} If some internal error took place inside the core layers.
*/
this.getRegistryNames = function (node) {
ensureNode(node, 'node');
return core.getRegistryNames(node);
};
/**
* Retrieves the value of the given registry entry of the given node.
* @param {module:Core~Node} node - the node in question.
* @param {string} name - the name of the registry entry.
*
* @return {string|number|bool|object|undefined} The function returns the value of the registry entry
* of the node. The value can be an object or any primitive type. If the value is undefined that means
* the node do not have such attribute defined.
*
* @throws {CoreIllegalArgumentError} If some of the parameters don't match the input criteria.
* @throws {CoreInternalError} If some internal error took place inside the core layers.
*/
this.getRegistry = function (node, name) {
ensureNode(node, 'node');
ensureType(name, 'name', 'string');
return core.copyIfObject(core.getRegistry(node, name));
};
/**
* Sets the value of the given registry entry of the given node. It defines the registry entry on demand,
* means that it will set the given registry entry even if was ot defined for the node beforehand.
* @param {module:Core~Node} node - the node in question.
* @param {string} name - the name of the registry entry.
* @param {string|number|bool|object} value - the new of the registry entry. Can be any primitive
* type or object. Undefined is not allowed.
*
* @throws {CoreIllegalArgumentError} If some of the parameters don't match the input criteria.
* @throws {CoreIllegalOperationError} If the context of the operation is not allowed.
* @throws {CoreInternalError} If some internal error took place inside the core layers.
*/
this.setRegistry = function (node, name, value) {
ensureNode(node, 'node');
ensureType(name, 'name', 'string');
ensureMongoCompatibleKey(name, 'name', true);
ensureValue(value, 'value');
return core.setRegistry(node, name, value);
};
/**
* Removes the given registry entry from the given node.
* @param {module:Core~Node} node - the node in question.
* @param {string} name - the name of the registry entry.
*
*
* @throws {CoreIllegalArgumentError} If some of the parameters don't match the input criteria.
* @throws {CoreIllegalOperationError} If the context of the operation is not allowed.
* @throws {CoreInternalError} If some internal error took place inside the core layers.
*/
this.delRegistry = function (node, name) {
ensureNode(node, 'node');
ensureType(name, 'name', 'string');
return core.delRegistry(node, name);
};
/**
* Retrieves a list of the defined pointer names of the node.
* @param {module:Core~Node} node - the node in question.
*
* @return {string[]} The function returns an array of the names of the pointers of the node.
*
* @throws {CoreIllegalArgumentError} If some of the parameters don't match the input criteria.
* @throws {CoreInternalError} If some intern