update from RIFT as of 696b75d2fe9fb046261b08c616f1bcf6c0b54a9b third try
[osm/UI.git] / skyquake / plugins / admin / src / components / editor / resolveLeafRef.js
1 function isRelativePath(path) {
2 if (path.split('/')[0] == '..') {
3 return true;
4 }
5 return false;
6 }
7
8 function getResults(topLevelObject, pathArray) {
9 let objectCopy = _cloneDeep(topLevelObject);
10 let i = pathArray.length;
11 let results = [];
12
13 while (pathArray[pathArray.length - i]) {
14 if (_isArray(objectCopy[pathArray[pathArray.length - i]])) {
15 if (i == 2) {
16 results = _map(objectCopy[pathArray[pathArray.length - i]], pathArray[pathArray.length - 1]);
17 } else {
18 objectCopy = objectCopy[pathArray[pathArray.length - i]];
19 }
20 } else if (_isArray(objectCopy)) {
21 objectCopy.map((object) => {
22 if (_isArray(object[pathArray[pathArray.length - i]])) {
23 if (i == 2) {
24 results = results.concat(_map(object[pathArray[pathArray.length - i]], pathArray[pathArray.length - 1]));
25 }
26 }
27 })
28 }
29 i--;
30 }
31
32 return results;
33 }
34
35 function getAbsoluteResults(topLevelObject, pathArray) {
36 let i = pathArray.length;
37 let objectCopy = _cloneDeep(topLevelObject);
38 let results = [];
39
40 let fragment = pathArray[pathArray.length - i]
41
42 while (fragment) {
43 if (i == 1) {
44 // last fragment
45 if (_isArray(objectCopy)) {
46 // results will be obtained from a map
47 results = _map(objectCopy, fragment);
48 } else {
49 // object
50 if (fragment.match(/\[.*\]/g)) {
51 // contains a predicate
52 // shouldn't reach here
53 console.log('Something went wrong while resolving a leafref. Reached a leaf with predicate.');
54 } else {
55 // contains no predicate
56 if (!objectCopy) {
57 break;
58 }
59 results.push(objectCopy[fragment]);
60 }
61 }
62 } else {
63 if (_isArray(objectCopy)) {
64 // is array
65 objectCopy = _map(objectCopy, fragment);
66
67 // If any of the deeper object is an array, flatten the entire list.
68 // This would usually be a bad leafref going out of its scope.
69 // Log it too
70 for (let i = 0; i < objectCopy.length; i++) {
71 if (_isArray(objectCopy[i])) {
72 objectCopy = _flatten(objectCopy);
73 console.log('This might be a bad leafref. Verify with backend team.')
74 break;
75 }
76 }
77 } else {
78 // is object
79 if (fragment.match(/\[.*\]/g)) {
80 // contains a predicate
81 let predicateStr = fragment.match(/\[.*\]/g)[0];
82 // Clip leading [ and trailing ]
83 predicateStr = predicateStr.substr(1, predicateStr.length - 2);
84 const predicateKeyValue = predicateStr.split('=');
85 const predicateKey = predicateKeyValue[0];
86 const predicateValue = predicateKeyValue[1];
87 // get key for object to search into
88 let key = fragment.split('[')[0];
89 let searchObject = {};
90 searchObject[predicateKey] = predicateValue;
91 let found = _find(objectCopy[key], searchObject);
92 if (found) {
93 objectCopy = found;
94 } else {
95 // check for numerical value
96 if (predicateValue != "" &&
97 predicateValue != null &&
98 predicateValue != NaN &&
99 predicateValue != Infinity &&
100 predicateValue != -Infinity) {
101 let numericalPredicateValue = _toNumber(predicateValue);
102 if (_isNumber(numericalPredicateValue)) {
103 searchObject[predicateKey] = numericalPredicateValue;
104 found = _find(objectCopy[key], searchObject);
105 }
106 }
107 if (found) {
108 objectCopy = found;
109 } else {
110 return [];
111 }
112 }
113 } else {
114 // contains no predicate
115 if (!objectCopy) {
116 break;
117 }
118 objectCopy = objectCopy[fragment];
119 if (!objectCopy) {
120 // contains no value
121 break;
122 }
123 }
124 }
125 }
126 i--;
127 fragment = pathArray[pathArray.length - i];
128 }
129
130 return results;
131 }
132
133 function resolveCurrentPredicate(leafRefPath, container, pathCopy) {
134 if (leafRefPath.indexOf('current()') != -1) {
135 // contains current
136
137 // Get the relative path from current
138 let relativePath = leafRefPath.match("current\\(\\)\/(.*)\]");
139 let relativePathArray = relativePath[1].split('/');
140
141 while (relativePathArray[0] == '..') {
142 pathCopy.pop();
143 relativePathArray.shift();
144 }
145
146 // Supports only one relative path up
147 // To support deeper paths, will need to massage the string more
148 // i.e. change '/'' to '.'
149 const searchPath = pathCopy.join('.').concat('.', relativePathArray[0]);
150 const searchValue = resolvePath(container.model, searchPath);
151
152 const predicateStr = leafRefPath.match("(current.*)\]")[1];
153 leafRefPath = leafRefPath.replace(predicateStr, searchValue);
154 }
155 return leafRefPath;
156 }
157
158 function cleanupFieldKeyArray (fieldKeyArray) {
159 fieldKeyArray.map((fieldKey, fieldKeyIndex) => {
160 fieldKeyArray[fieldKeyIndex] = fieldKey.replace(/.*\/(.*)/, '$1');
161 });
162 return fieldKeyArray;
163 }
164
165 export default function resolveLeafRefPath(catalogs, leafRefPath, fieldKey, path, container) {
166 let pathCopy = _clone(path);
167 // Strip any prefixes
168 let leafRefPathCopy = leafRefPath.replace(/[\w\d]*:/g, '');
169 // Strip any spaces
170 leafRefPathCopy = leafRefPathCopy.replace(/\s/g, '');
171
172 // resolve any current paths
173 leafRefPathCopy = resolveCurrentPredicate(leafRefPathCopy, container, pathCopy);
174
175 // Split on delimiter (/)
176 const pathArray = leafRefPathCopy.split('/');
177
178 let fieldKeyArray = fieldKey.split(':');
179
180 // strip prepending qualifiers from fieldKeys
181 fieldKeyArray = cleanupFieldKeyArray(fieldKeyArray);
182 let results = [];
183
184 // Check if relative path or not
185 // TODO: Below works but
186 // better to convert the pathCopy to absolute/rooted path
187 // and use the absolute module instead
188 if (isRelativePath(leafRefPathCopy)) {
189 let i = pathArray.length;
190 while (pathArray[pathArray.length - i] == '..') {
191 fieldKeyArray.splice(-1, 1);
192 if (!isNaN(Number(fieldKeyArray[fieldKeyArray.length - 1]))) {
193 // found a number, so an index. strip it
194 fieldKeyArray.splice(-1, 1);
195 }
196 i--;
197 }
198
199 // traversed all .. - now traverse down
200 if (fieldKeyArray.length == 1) {
201 for (let key in catalogs) {
202 for (let subKey in catalogs[key]) {
203 let found = _find(catalogs[key][subKey], {
204 id: fieldKeyArray[0]
205 });
206 if (found) {
207 results = getAbsoluteResults(found, pathArray.splice(-i, i));
208 return results;
209 }
210 }
211 }
212 } else if (fieldKeyArray.length == 2) {
213 for (let key in catalogs) {
214 for (let subKey in catalogs[key]) {
215 console.log(key, subKey);
216 var found = _find(catalogs[key][subKey], {
217 id: fieldKeyArray[0]
218 });
219 if (found) {
220 for (let foundKey in found) {
221 if (_isArray(found[foundKey])) {
222 let topLevel = _find(found[foundKey], {
223 id: fieldKeyArray[1]
224 });
225 if (topLevel) {
226 results = getAbsoluteResults(topLevel, pathArray.splice(-i, i));
227 return results;
228 }
229 } else {
230 if (foundKey == fieldKeyArray[1]) {
231 results = getAbsoluteResults(found[foundKey], pathArray.splice(-i, i));
232 return results;
233 }
234 }
235 }
236 }
237 }
238 }
239 } else if (fieldKeyArray.length == 3) {
240 for (let key in catalogs) {
241 for (let subKey in catalogs[key]) {
242 let found = _find(catalogs[key][subKey], {
243 id: fieldKeyArray[0]
244 });
245 if (found) {
246 for (let foundKey in found) {
247 if (_isArray(found[foundKey])) {
248 let topLevel = _find(found[foundKey], {
249 id: fieldKeyArray[1]
250 });
251 if (topLevel) {
252 results = getAbsoluteResults(topLevel, pathArray.splice(-i, i));
253 return results;
254 }
255 } else {
256 if (foundKey == fieldKeyArray[1]) {
257 results = getAbsoluteResults(found[foundKey], pathArray.splice(-i, i));
258 return results;
259 }
260 }
261 }
262 }
263 }
264 }
265 } else {
266 // not supported - too many levels deep ... maybe some day
267 console.log('The relative path is from a node too many levels deep from root. This is not supported at the time');
268 }
269 } else {
270 // absolute path
271 if (pathArray[0] == "") {
272 pathArray.splice(0, 1);
273 }
274
275 let catalogKey = pathArray[0];
276 let topLevelObject = {};
277
278 topLevelObject[catalogKey] = catalogs[catalogKey];
279
280 results = getAbsoluteResults(topLevelObject, pathArray);
281
282 return results;
283 }
284 }