Yangutils - uses statement can be root
[dlux.git] / modules / common-yangutils-resources / src / main / resources / yangutils / services / module-connector.services.js
1 define([], function () {
2     'use strict';
3
4     function ModuleConnectorService(){
5
6         var service = {
7                 processModuleObjs: processModuleObjs,
8                 __test: {
9                     isBuildInType: isBuildInType,
10                     linkFunctions: linkFunctions,
11                     findLinkedStatement: findLinkedStatement,
12                     appendChildren: appendChildren,
13                     searchModule: searchModule,
14                     applyLinks: applyLinks,
15                     interConnectModules: interConnectModules,
16                     applyModuleRevision: applyModuleRevision,
17                 },
18             },
19             linkFunctions = {
20                 uses: uses,
21                 type: type,
22             };
23
24         return service;
25
26         // TODO: add service's description
27         function processModuleObjs(modules) {
28             var rootNodes = [],
29                 augments = [],
30                 connectedModules = interConnectModules(modules.slice());
31
32             connectedModules.forEach(function (module) {
33                 rootNodes = rootNodes.concat(module.getRoots());
34                 augments = augments.concat(module.getAugments());
35             });
36
37             return { rootNodes: rootNodes, augments: augments };
38         }
39
40         // TODO: add function's description
41         function uses(usesNode, currentModule, parentNode) {
42             var targetType = 'grouping';
43             return function (modules) {
44                 var data = findLinkedStatement(usesNode, targetType, currentModule, modules),
45                     node = data.node,
46                     module = data.module,
47                     changed = false;
48
49                 if (node && module) {
50                     if (usesNode.parent.children) { // if parent is node
51                         usesNode.parent.children.splice(usesNode.parent.children.indexOf(usesNode), 1); // delete uses node
52                     }
53                     else if (usesNode.parent._roots) { // if parent is module
54                         usesNode.parent._roots.splice(usesNode.parent._roots.indexOf(usesNode), 1);
55                     }
56                     for (var i = 0; i < node.children.length; i++) {
57                         applyLinks(node.children[i], module, modules);
58                     }
59                     appendChildren(usesNode.parent, node);
60                     changed = true;
61                 }
62
63                 return changed;
64             };
65         }
66
67         // TODO: add function's description
68         function type(typeNode, currentModule, parentNode) {
69             var targetType = 'typedef';
70
71             if (isBuildInType(typeNode.label) === false) {
72                 return function (modules) {
73                     var data = findLinkedStatement(typeNode, targetType, currentModule, modules),
74                         node = data.node ? data.node.getChildren('type')[0] : null,
75                         changed = false;
76
77                     if (node) {
78                         // delete referencing type node
79
80                         parentNode.children.splice(typeNode.parent.children.indexOf(typeNode), 1);
81                         parentNode.addChild(node);
82                         changed = true;
83                     }
84
85                     return changed;
86                 };
87             } else {
88                 return function (modules) {
89                     return false;
90                 };
91             }
92         }
93
94         // TODO: add function's description
95         function isBuildInType(type) {
96             return ['int8', 'int16', 'int32', 'int64', 'uint8', 'uint16', 'uint32', 'uint64',
97                     'decimal64', 'string', 'boolean', 'enumeration', 'bits', 'binary',
98                     'leafref', 'identityref', 'empty', 'union', 'instance-identifier'].indexOf(type) > -1;
99         }
100
101         // TODO: add function's description
102         function findLinkedStatement(node, targetType, currentModule, modules) {
103             var sourceNode,
104                 sourceModule,
105                 link = node.label;
106
107             if (link.indexOf(':') > -1) {
108                 var parts = link.split(':'),
109                     targetImport = currentModule.getImportByPrefix(parts[0]);
110
111                 sourceModule = targetImport ?
112                                     searchModule(modules, targetImport.label, targetImport.revisionDate) : null;
113                 sourceNode = sourceModule ? sourceModule.searchNode(targetType, parts[1]) : null;
114             } else {
115                 sourceModule = searchModule(modules, node.module, node.moduleRevision);
116                 sourceNode = sourceModule ? sourceModule.searchNode(targetType, link) : null;
117             }
118
119             return { node: sourceNode, module: sourceModule };
120         }
121
122         // TODO: add function's description
123         function appendChildren(targetNode, sourceNode) {
124             sourceNode.children.forEach(function (child) {
125                 targetNode.addChild(child);
126             });
127         }
128
129         // TODO: add function's description
130         function searchModule(modules, moduleName, moduleRevision) {
131             var searchResults = modules.filter(function (item) {
132                     return (moduleName === item._name && (moduleRevision ? moduleRevision === item._revision : true));
133                 }),
134                 targetModule = (searchResults && searchResults.length) ? searchResults[0] : null;
135
136             return targetModule;
137         }
138
139         // TODO: add function's description
140         function applyLinks(node, module, modules, parentNode) {
141             var changed = false;
142             if (linkFunctions.hasOwnProperty(node.type)) { // applying link function to uses.node
143                 changed = linkFunctions[node.type](node, module, parentNode)(modules);
144             }
145
146             for (var i = 0; i < node.children.length; i++) {
147                 if (applyLinks(node.children[i], module, modules, node)) {
148                     i--;
149                     // need to repeat current index because we are deleting uses nodes,
150                     // so in case there are more uses in row, it would skip second one
151                 }
152             }
153
154             return changed;
155         }
156
157         // TODO: add function's description
158         function interConnectModules(modules) {
159
160             modules.forEach(function (module) {
161                 module.getRoots().concat(module.getRawAugments()).forEach(function (node) {
162                     applyLinks(node, module, modules);
163                 });
164             });
165
166             modules.forEach(function (module) {
167                 var copy = null;
168
169                 module._roots = module.getRoots().map(function (node) {
170                     copy = node.deepCopy();
171                     return applyModuleRevision(copy, module._name, module._revision);
172                 });
173
174                 module._augments = module.getRawAugments().map(function (node) {
175                     copy = node.deepCopy();
176                     return applyModuleRevision(copy, module._name, module._revision);
177                 });
178             });
179
180             return modules;
181         }
182
183         // TODO: add function's description
184         function applyModuleRevision(node, module, revision) {
185             node.module = module;
186             node.moduleRevision = revision;
187
188             node.children.map(function (child) {
189                 return applyModuleRevision(child, module, revision);
190             });
191
192             return node;
193         }
194     }
195
196     ModuleConnectorService.$inject = [];
197
198     return ModuleConnectorService;
199
200 });