webgme-engine
Version:
WebGME server and Client API without a GUI
523 lines (442 loc) • 19.4 kB
JavaScript
/*globals define*/
/*eslint-env node, browser*/
/**
* @author kecso / https://github.com/kecso
*/
define(['q'], function (Q) {
'use strict';
/**
* Propagates a recent renaming in a meta definition of the given node. It traverses the
* whole containment hierarchy and renames the corresponding property of every node that is
* affected by the rename. It is important that the rename should always take place after the
* actual definition was already changed among the meta definitions of the node.
* @param core
* @param node - any node in tree to be checked
* @param parameters
* @param [callback]
* @returns {Q.Promise}
*/
function propagateMetaDefinitionRename(core, node, parameters, callback) {
var deferred = Q.defer(),
nodePath = core.getPath(node),
visitFn;
function visitForAttribute(visited, next) {
if (parameters.excludeOriginNode === true && core.getPath(visited) === nodePath) {
next(null);
return;
}
if (core.getValidAttributeNames(visited).indexOf(parameters.newName) === -1 ||
core.getOwnAttributeNames(visited).indexOf(parameters.oldName) === -1) {
next(null);
return;
}
if (core.getPath(core.getAttributeDefinitionOwner(visited, parameters.newName)) === nodePath) {
core.renameAttribute(visited, parameters.oldName, parameters.newName);
}
next(null);
}
function visitForPointer(visited, next) {
var definitionInfo,
deferred = Q.defer();
if (parameters.excludeOriginNode === true && core.getPath(visited) === nodePath) {
return Q.resolve(null).nodeify(next);
}
if (core.getValidPointerNames(visited).indexOf(parameters.newName) === -1 ||
core.getOwnPointerPath(visited, parameters.oldName) === undefined) {
return Q.resolve(null).nodeify(next);
}
core.loadPointer(visited, parameters.oldName)
.then(function (target) {
if (target !== null) {
definitionInfo = core.getPointerDefinitionInfo(visited, parameters.newName, target);
if (definitionInfo.ownerPath === nodePath &&
definitionInfo.targetPath === parameters.targetPath) {
core.renamePointer(visited, parameters.oldName, parameters.newName);
}
} else if (core.getPath(visited) === nodePath) {
core.renamePointer(visited, parameters.oldName, parameters.newName);
}
deferred.resolve(null);
})
.catch(deferred.reject);
return deferred.promise.nodeify(next);
}
function visitForSet(visited, next) {
var definitionInfo,
deferred = Q.defer();
if (parameters.excludeOriginNode === true && core.getPath(visited) === nodePath) {
return Q.resolve(null).nodeify(next);
}
if (core.getValidSetNames(visited).indexOf(parameters.newName) === -1 ||
core.getOwnSetNames(visited, parameters.oldName).indexOf(parameters.oldName) === -1) {
return Q.resolve(null).nodeify(next);
}
core.loadOwnMembers(visited, parameters.oldName)
.then(function (members) {
var i,
ownMemberPaths = core.getOwnMemberPaths(visited, parameters.oldName);
for (i = 0; i < members.length; i += 1) {
if (ownMemberPaths.indexOf(core.getPath(members[i])) !== -1) {
definitionInfo = core.getSetDefinitionInfo(visited, parameters.newName, members[i]);
if (definitionInfo.ownerPath === nodePath &&
definitionInfo.targetPath === parameters.targetPath) {
core.moveMember(visited, core.getPath(members[i]),
parameters.oldName, parameters.newName);
}
}
}
if (members.length === 0) {
core.renameSet(visited, parameters.oldName, parameters.newName);
}
deferred.resolve(null);
return;
})
.catch(deferred.reject);
return deferred.promise.nodeify(next);
}
function visitForAspect(visited, next) {
var definitionInfo,
deferred = Q.defer();
if (parameters.excludeOriginNode === true && core.getPath(visited) === nodePath) {
next(null);
return;
}
if (core.getValidAspectNames(visited).indexOf(parameters.newName) === -1 ||
core.getOwnSetNames(visited).indexOf(parameters.oldName) === -1) {
next(null);
return;
}
core.loadMembers(visited, parameters.oldName)
.then(function (members) {
var i;
for (i = 0; i < members.length; i += 1) {
definitionInfo = core.getAspectDefinitionInfo(visited, parameters.newName, members[i]);
if (definitionInfo.ownerPath === nodePath &&
definitionInfo.targetPath === parameters.targetPath) {
core.moveMember(visited, core.getPath(members[i]), parameters.oldName, parameters.newName);
}
}
deferred.resolve(null);
return;
})
.catch(deferred.reject);
return deferred.promise.nodeify(next);
}
switch (parameters.type) {
case 'attribute':
visitFn = visitForAttribute;
break;
case 'pointer':
visitFn = visitForPointer;
break;
case 'set':
visitFn = visitForSet;
break;
case 'aspect':
visitFn = visitForAspect;
break;
default:
return Q.reject(new Error('Invalid parameter misses a correct type for renaming.')).nodeify(callback);
}
core.traverse(core.getRoot(node), {excludeRoot: true, stopOnError: true}, visitFn)
.then(deferred.resolve)
.catch(deferred.reject);
return deferred.promise.nodeify(callback);
}
function _areTheTwoConceptsConnected(core, conceptOne, conceptTwo) {
var allMetaNodes,
path;
if (core.isTypeOf(conceptOne, conceptTwo)) {
return true;
}
if (core.isTypeOf(conceptTwo, conceptOne)) {
return true;
}
allMetaNodes = core.getAllMetaNodes(conceptOne);
for (path in allMetaNodes) {
if (core.isTypeOf(allMetaNodes[path], conceptOne) && core.isTypeOf(allMetaNodes[path], conceptTwo)) {
return true;
}
}
return false;
}
function _collectedBasicAffectedTypes(core, node, type, name) {
var affectedTypes = [],
allMetaNodes = core.getAllMetaNodes(node),
checkerFunc,
check = function (node) {
return checkerFunc(node).indexOf(name) !== -1;
},
path;
switch (type) {
case 'attribute':
checkerFunc = core.getOwnValidAttributeNames;
break;
case 'pointer':
checkerFunc = core.getOwnValidPointerNames;
break;
case 'set':
checkerFunc = core.getOwnValidSetNames;
break;
case 'aspect':
checkerFunc = core.getOwnValidAspectNames;
break;
default:
return null;
}
for (path in allMetaNodes) {
if (_areTheTwoConceptsConnected(core, node, allMetaNodes[path]) && check(allMetaNodes[path])) {
affectedTypes.push(allMetaNodes[path]);
}
}
return affectedTypes;
}
function _instanceOfAny(core, node, types) {
var i;
for (i = 0; i < types.length; i += 1) {
if (core.isTypeOf(node, types[i])) {
return true;
}
}
return false;
}
function metaConceptRenameInMeta(core, node, type, oldName, newName) {
var affectedTypes,
toArrayFunc,
allMetaNodes = core.getAllMetaNodes(node),
checkerFunction = function (typeNode) {
return toArrayFunc(typeNode).indexOf(oldName) !== -1;
},
i,
targets,
path;
switch (type) {
case 'attribute':
toArrayFunc = core.getOwnValidAttributeNames;
break;
case 'pointer':
toArrayFunc = core.getOwnValidPointerNames;
break;
case 'set':
toArrayFunc = core.getOwnValidSetNames;
break;
case 'aspect':
toArrayFunc = core.getOwnValidAspectNames;
break;
default:
return null;
}
affectedTypes = _collectedBasicAffectedTypes(core, node, type, oldName);
if (affectedTypes === null) {
return null;
}
for (path in allMetaNodes) {
if (_instanceOfAny(core, allMetaNodes[path], affectedTypes) &&
checkerFunction(allMetaNodes[path])) {
switch (type) {
case 'attribute':
core.renameAttributeMeta(allMetaNodes[path], oldName, newName);
break;
case 'pointer':
case 'set':
targets = core.getOwnValidTargetPaths(allMetaNodes[path], oldName);
for (i = 0; i < targets.length; i += 1) {
core.movePointerMetaTarget(allMetaNodes[path], allMetaNodes[targets[i]], oldName, newName);
}
break;
case 'aspect':
targets = core.getOwnValidAspectTargetPaths(allMetaNodes[path], oldName);
for (i = 0; i < targets.length; i += 1) {
core.moveAspectMetaTarget(allMetaNodes[path], allMetaNodes[targets[i]], oldName, newName);
}
}
}
}
}
function propagateMetaConceptRename(core, typeNodes, type, oldName, newName, callback) {
var deferred = Q.defer(),
hasDataFn,
hasData = function (node) {
return hasDataFn(node).indexOf(oldName) !== -1;
},
renameFn,
visitFn = function (visitedNode, next) {
if (_instanceOfAny(core, visitedNode, typeNodes) && hasData(visitedNode)) {
renameFn(visitedNode, oldName, newName);
}
next(null);
},
i;
switch (type) {
case 'attribute':
renameFn = core.renameAttribute;
hasDataFn = core.getOwnAttributeNames;
break;
case 'pointer':
renameFn = core.renamePointer;
hasDataFn = core.getOwnPointerNames;
break;
case 'set':
case 'aspect':
renameFn = core.renameSet;
hasDataFn = core.getOwnSetNames;
break;
default:
return Q.reject(new Error('Unkown rule type [' + type + ']')).nodeify(callback);
}
// check if the affected types are in some library as they cannot be changed...
for (i = 0; i < typeNodes.length; i += 1) {
if (core.isLibraryElement(typeNodes[i])) {
return Q.reject(new Error('Concept originates in some library therefore cannot be renamed!'))
.nodeify(callback);
}
}
core.traverse(core.getRoot(typeNodes[0]), {excludeRoot: true, stopOnError: true}, visitFn)
.then(deferred.resolve)
.catch(deferred.reject);
return deferred.promise.nodeify(callback);
}
function metaConceptRename(core, node, type, oldName, newName, callback) {
var deferred = Q.defer(),
affectedTypes = _collectedBasicAffectedTypes(core, node, type, oldName),
i;
if (affectedTypes === null) {
return Q.reject(new Error('Unknown rule type [' + type + ']')).nodeify(callback);
}
// check if the affected types are in some library as they cannot be changed...
for (i = 0; i < affectedTypes.length; i += 1) {
if (core.isLibraryElement(affectedTypes[i])) {
return Q.reject(new Error('Concept originates in some library therefore cannot be renamed!'))
.nodeify(callback);
}
}
propagateMetaConceptRename(core, affectedTypes, type, oldName, newName)
.then(function () {
metaConceptRenameInMeta(core, node, type, oldName, newName);
return deferred.resolve();
})
.catch(deferred.reject);
return deferred.promise.nodeify(callback);
}
function propagateMetaDefinitionRemove(core, node, parameters, callback) {
var deferred = Q.defer(),
visitFn;
function visitForAttribute(visited, next) {
if (core.getOwnAttributeNames(visited).indexOf(parameters.name) !== -1 &&
core.getValidAttributeNames(visited).indexOf(parameters.name) === -1) {
core.delAttribute(visited, parameters.name);
}
next(null);
}
function visitForPointer(visited, next) {
var deferred = Q.defer();
if (core.getOwnPointerPath(visited, parameters.name) === undefined) {
return Q.resolve(null).nodeify(next);
}
if (core.getValidPointerNames(visited).indexOf(parameters.name) === -1) {
core.deletePointer(visited, parameters.name);
return Q.resolve(null).nodeify(next);
}
core.loadPointer(visited, parameters.name)
.then(function (target) {
if (target !== null && core.isValidTargetOf(target, visited, parameters.name) === false) {
core.deletePointer(visited, parameters.name);
}
deferred.resolve(null);
})
.catch(deferred.reject);
return deferred.promise.nodeify(next);
}
function visitForSet(visited, next) {
var deferred = Q.defer();
if (core.getOwnSetNames(visited).indexOf(parameters.name) === -1) {
return Q.resolve(null).nodeify(next);
}
if (core.getValidSetNames(visited).indexOf(parameters.name) === -1) {
core.deleteSet(visited, parameters.name);
return Q.resolve(null).nodeify(next);
}
core.loadOwnMembers(visited, parameters.name)
.then(function (members) {
var i, removed = 0;
for (i = 0; i < members.length; i += 1) {
if (core.isValidTargetOf(members[i], visited, parameters.name) === false) {
core.delMember(visited, parameters.name, core.getPath(members[i]));
removed += 1;
}
}
if (members.length === removed) {
core.deleteSet(visited, parameters.name);
}
deferred.resolve(null);
})
.catch(deferred.reject);
return deferred.promise.nodeify(next);
}
function visitForAspect(visited, next) {
var deferred = Q.defer();
//isValidAspectMemberOf
if (core.getOwnSetNames(visited).indexOf(parameters.name) !== -1) {
if (core.getValidAspectNames(visited).indexOf(parameters.name) === -1) {
core.delSet(visited, parameters.name);
return Q.resolve(null).nodeify(next);
}
core.loadMembers(visited, parameters.name)
.then(function (members) {
var i, removed = 0;
for (i = 0; i < members.length; i += 1) {
if (core.isValidAspectMemberOf(members[i], visited, parameters.name) === false) {
core.delMember(visited, parameters.name, core.getPath(members[i]));
removed += 1;
}
}
if (members.length === removed) {
core.deleteSet(visited, parameters.name);
}
deferred.resolve(null);
})
.catch(deferred.reject);
} else {
return Q.resolve(null).nodeify(next);
}
return deferred.promise.nodeify(next);
}
function visitForContainment(visited, next) {
var parent = core.getParent(visited);
if (parent !== null && core.isValidChildOf(visited, parent) === false) {
core.deleteNode(visited);
}
next(null);
}
switch (parameters.type) {
case 'attribute':
visitFn = visitForAttribute;
break;
case 'pointer':
visitFn = visitForPointer;
break;
case 'set':
visitFn = visitForSet;
break;
case 'aspect':
visitFn = visitForAspect;
break;
case 'containment':
visitFn = visitForContainment;
break;
default:
return Q.reject(new Error('Invalid parameter misses a correct type for renaming.')).nodeify(callback);
}
core.traverse(core.getRoot(node), {excludeRoot: true, stopOnError: true}, visitFn)
.then(deferred.resolve)
.catch(deferred.reject);
return deferred.promise.nodeify(callback);
}
return {
propagateMetaDefinitionRename: propagateMetaDefinitionRename,
metaConceptRename: metaConceptRename,
metaConceptRenameInMeta: metaConceptRenameInMeta,
propagateMetaConceptRename: propagateMetaConceptRename,
propagateMetaDefinitionRemove: propagateMetaDefinitionRemove
};
});