fix(#6549): [StaticRootPlugin] Remap non-empty root namespaces and non-root namespaces correctly (#6583)

* fix: preserve truthy namespaces and unmapped values

- Fixes the issue of the Static Root provider overriding existing namespaces, such as those from a telemetry dictionary
- Fixes the issue of keys of child objects NOT present in the idMapping (such as those from a telemetry dictionary) being overwritten as undefined
- TODO: This will not work for objects exported from an environment that has the "MyItems" namespace defined to anything other than an empty string. Need to figure out how to handle this.

* fix: handle the case of rootId having a namespace !== ""

* refactor: use `parseKeyString`

* fix: StaticRootPlugin object mapping for non-empty namespaces

* fix: use index, fix location identifiers

* tets: add non-empty namespace tests (wip)

* refactor: rename and move test files

* test: update StaticModelProvider tests

* fix: remap to identifiers for config, not keystring

---------

Co-authored-by: Khalid Adil <khalidadil29@gmail.com>
This commit is contained in:
Jesse Mazzella
2023-04-14 16:31:04 -07:00
committed by GitHub
parent a9a98380f2
commit dbdc9bb4e2
4 changed files with 282 additions and 126 deletions

View File

@@ -46,76 +46,96 @@ class StaticModelProvider {
throw new Error(keyString + ' not found in import models.');
}
parseObjectLeaf(objectLeaf, idMap, namespace) {
parseObjectLeaf(objectLeaf, idMap, newRootNamespace, oldRootNamespace) {
Object.keys(objectLeaf).forEach((nodeKey) => {
if (idMap.get(nodeKey)) {
const newIdentifier = objectUtils.makeKeyString({
namespace,
namespace: newRootNamespace,
key: idMap.get(nodeKey)
});
objectLeaf[newIdentifier] = { ...objectLeaf[nodeKey] };
delete objectLeaf[nodeKey];
objectLeaf[newIdentifier] = this.parseTreeLeaf(newIdentifier, objectLeaf[newIdentifier], idMap, namespace);
objectLeaf[newIdentifier] = this.parseTreeLeaf(newIdentifier, objectLeaf[newIdentifier], idMap, newRootNamespace, oldRootNamespace);
} else {
objectLeaf[nodeKey] = this.parseTreeLeaf(nodeKey, objectLeaf[nodeKey], idMap, namespace);
objectLeaf[nodeKey] = this.parseTreeLeaf(nodeKey, objectLeaf[nodeKey], idMap, newRootNamespace, oldRootNamespace);
}
});
return objectLeaf;
}
parseArrayLeaf(arrayLeaf, idMap, namespace) {
parseArrayLeaf(arrayLeaf, idMap, newRootNamespace, oldRootNamespace) {
return arrayLeaf.map((leafValue, index) => this.parseTreeLeaf(
null, leafValue, idMap, namespace));
null, leafValue, idMap, newRootNamespace, oldRootNamespace));
}
parseBranchedLeaf(branchedLeafValue, idMap, namespace) {
parseBranchedLeaf(branchedLeafValue, idMap, newRootNamespace, oldRootNamespace) {
if (Array.isArray(branchedLeafValue)) {
return this.parseArrayLeaf(branchedLeafValue, idMap, namespace);
return this.parseArrayLeaf(branchedLeafValue, idMap, newRootNamespace, oldRootNamespace);
} else {
return this.parseObjectLeaf(branchedLeafValue, idMap, namespace);
return this.parseObjectLeaf(branchedLeafValue, idMap, newRootNamespace, oldRootNamespace);
}
}
parseTreeLeaf(leafKey, leafValue, idMap, namespace) {
parseTreeLeaf(leafKey, leafValue, idMap, newRootNamespace, oldRootNamespace) {
if (leafValue === null || leafValue === undefined) {
return leafValue;
}
const hasChild = typeof leafValue === 'object';
if (hasChild) {
return this.parseBranchedLeaf(leafValue, idMap, namespace);
return this.parseBranchedLeaf(leafValue, idMap, newRootNamespace, oldRootNamespace);
}
if (leafKey === 'key') {
return idMap.get(leafValue);
} else if (leafKey === 'namespace') {
return namespace;
} else if (leafKey === 'location') {
if (idMap.get(leafValue)) {
const newLocationIdentifier = objectUtils.makeKeyString({
namespace,
key: idMap.get(leafValue)
});
return newLocationIdentifier;
let mappedLeafValue;
if (oldRootNamespace) {
mappedLeafValue = idMap.get(objectUtils.makeKeyString({
namespace: oldRootNamespace,
key: leafValue
}));
} else {
mappedLeafValue = idMap.get(leafValue);
}
return null;
} else if (idMap.get(leafValue)) {
const newIdentifier = objectUtils.makeKeyString({
namespace,
key: idMap.get(leafValue)
return mappedLeafValue ?? leafValue;
} else if (leafKey === 'namespace') {
// Only rewrite the namespace if it matches the old root namespace.
// This is to prevent rewriting namespaces of objects that are not
// children of the root object (e.g.: objects from a telemetry dictionary)
return leafValue === oldRootNamespace
? newRootNamespace
: leafValue;
} else if (leafKey === 'location') {
const mappedLeafValue = idMap.get(leafValue);
if (!mappedLeafValue) {
return null;
}
const newLocationIdentifier = objectUtils.makeKeyString({
namespace: newRootNamespace,
key: mappedLeafValue
});
return newIdentifier;
return newLocationIdentifier;
} else {
return leafValue;
const mappedLeafValue = idMap.get(leafValue);
if (mappedLeafValue) {
const newIdentifier = objectUtils.makeKeyString({
namespace: newRootNamespace,
key: mappedLeafValue
});
return newIdentifier;
} else {
return leafValue;
}
}
}
rewriteObjectIdentifiers(importData, rootIdentifier) {
const namespace = rootIdentifier.namespace;
const { namespace: oldRootNamespace } = objectUtils.parseKeyString(importData.rootId);
const { namespace: newRootNamespace } = rootIdentifier;
const idMap = new Map();
const objectTree = importData.openmct;
@@ -128,7 +148,7 @@ class StaticModelProvider {
idMap.set(originalId, newId);
});
const newTree = this.parseTreeLeaf(null, objectTree, idMap, namespace);
const newTree = this.parseTreeLeaf(null, objectTree, idMap, newRootNamespace, oldRootNamespace);
return newTree;
}