Skip to content

Commit

Permalink
Allow omitting keys during export toJSON. Fix #34
Browse files Browse the repository at this point in the history
  • Loading branch information
umesh-timalsina committed Sep 6, 2022
1 parent 89a7254 commit 420edf1
Show file tree
Hide file tree
Showing 2 changed files with 170 additions and 63 deletions.
194 changes: 131 additions & 63 deletions src/common/JSONImporter.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,25 @@ define([
);
}

async toJSON (node, shallow=false) {
async toJSON(node, omit=new Set()) {
if(!omit) {
omit = new Set();
} // Sentinel

if(typeof omit === 'string') {
omit = new Set([omit]);
}

if(typeof omit === 'boolean' && omit === true) {
omit = new Set(['children']);
} // Backwards compatible with shallow

if(Array.isArray(omit)) {
omit = new Set(omit);
}

['id', 'path', 'guid'].forEach(attr => omit.delete(attr));

const json = {
id: this.core.getGuid(node),
path: this.core.getPath(node),
Expand All @@ -41,80 +59,130 @@ define([
sets: {},
member_attributes: {},
member_registry: {},
children: [],
children_meta: {},
};
const asyncTasks = [];

this.core.getOwnAttributeNames(node).forEach(name => {
json.attributes[name] = this.core.getAttribute(node, name);
});
if(omit.has('sets')) {
omit.add('member_attributes');
omit.add('member_registry');
}

this.core.getOwnValidAttributeNames(node).forEach(name => {
json.attribute_meta[name] = this.core.getAttributeMeta(node, name);
});
if(omit.has('children')) {
omit.add('children_meta');
}

asyncTasks.push(...this.core.getOwnPointerNames(node).map(async name => {
const path = this.core.getPointerPath(node, name);
if (path) {
const target = await this.core.loadByPath(this.rootNode, path);
json.pointers[name] = this.core.getGuid(target);
} else {
json.pointers[name] = path;
}
}));
const baseNode = this.core.getBase(node);
json.pointers.base = baseNode && this.core.getGuid(baseNode);
json.mixins = Object.values(this.core.getMixinNodes(node)).map(node => this.core.getGuid(node));

asyncTasks.push(...this.core.getOwnValidPointerNames(node).map(async name => {
const ptr_meta = this.core.getPointerMeta(node, name);
json.pointer_meta[name] = await this._metaDictToGuids(ptr_meta);
}));

this.core.getOwnRegistryNames(node).forEach(name => {
json.registry[name] = this.core.getRegistry(node, name);
});
omit.forEach(key => delete json[key]);

asyncTasks.push(...this.core.getOwnSetNames(node)
.filter(name => name !== '_mixins')
.map(async name => {
const paths = this.core.getMemberPaths(node, name);
const members = await Promise.all(paths.map(path => this.core.loadByPath(this.rootNode, path)));
const memberGuids = members.map(member => this.core.getGuid(member));
json.sets[name] = memberGuids;

members.forEach(member => {
let guid = this.core.getGuid(member);
let memberPath = this.core.getPath(member);
json.member_attributes[name] = {};
json.member_attributes[name][guid] = {};

this.core.getMemberAttributeNames(node, name, memberPath).forEach(attrName => {
const value = this.core.getMemberAttribute(node, name, memberPath, attrName);
json.member_attributes[name][guid][attrName] = value;
const asyncTasks = [];

const exporters = {
attributes: (node, json, /*promiseQueue*/) => {
this.core.getOwnAttributeNames(node).forEach(name => {
json.attributes[name] = this.core.getAttribute(node, name);
});
},

json.member_registry[name] = {};
json.member_registry[name][guid] = {};
this.core.getMemberRegistryNames(node, name, memberPath).forEach(regName => {
const value = this.core.getMemberRegistry(node, name, memberPath, regName);
json.member_registry[name][guid][regName] = value;
attribute_meta: (node, json, /*promiseQueue*/) => {
this.core.getOwnValidAttributeNames(node).forEach(name => {
json.attribute_meta[name] = this.core.getAttributeMeta(node, name);
});
});
}));
},

if (!shallow) {
json.children = [];
const children = await this.core.loadChildren(node);
for (let i = 0; i < children.length; i++) {
json.children.push(await this.toJSON(children[i]));
pointers: (node, json, promiseQueue) => {
promiseQueue.push(...this.core.getOwnPointerNames(node).map(async name => {
const path = this.core.getPointerPath(node, name);
if (path) {
const target = await this.core.loadByPath(this.rootNode, path);
json.pointers[name] = this.core.getGuid(target);
} else {
json.pointers[name] = path;
}
}));
const baseNode = this.core.getBase(node);
json.pointers.base = baseNode && this.core.getGuid(baseNode);
},

mixins: (node, json, /*promiseQueue*/) => {
json.mixins = Object.values(this.core.getMixinNodes(node)).map(node => this.core.getGuid(node));
},

pointer_meta: (node, json, promiseQueue) => {
promiseQueue.push(...this.core.getOwnValidPointerNames(node).map(async name => {
const ptr_meta = this.core.getPointerMeta(node, name);
json.pointer_meta[name] = await this._metaDictToGuids(ptr_meta);
}));
},

registry: (node, json, /*promiseQueue*/) => {
this.core.getOwnRegistryNames(node).forEach(name => {
json.registry[name] = this.core.getRegistry(node, name);
});
},

sets: (node, json, promiseQueue) => {
promiseQueue.push(...this.core.getOwnSetNames(node)
.filter(name => name !== '_mixins')
.map(async name => {
const paths = this.core.getMemberPaths(node, name);
const members = await Promise.all(paths.map(path => this.core.loadByPath(this.rootNode, path)));
const memberGuids = members.map(member => this.core.getGuid(member));
json.sets[name] = memberGuids;

if (!omit.has('member_attributes')) { // Alternatives to this closure variable?
members.forEach(member => {
let guid = this.core.getGuid(member);
let memberPath = this.core.getPath(member);

json.member_attributes[name] = {};
json.member_attributes[name][guid] = {};
this.core.getMemberAttributeNames(node, name, memberPath).forEach(attrName => {
const value = this.core.getMemberAttribute(node, name, memberPath, attrName);
json.member_attributes[name][guid][attrName] = value;
});
});
}
if (!omit.has('member_registry')) {
members.forEach(member => {
let guid = this.core.getGuid(member);
let memberPath = this.core.getPath(member);

json.member_registry[name] = {};
json.member_registry[name][guid] = {};
this.core.getMemberRegistryNames(node, name, memberPath).forEach(regName => {
const value = this.core.getMemberRegistry(node, name, memberPath, regName);
json.member_registry[name][guid][regName] = value;
});
});
}

}));
},

children: (node, json, promiseQueue) => {
promiseQueue.push((async () => {
json.children = [];
const children = await this.core.loadChildren(node);
for (let i = 0; i < children.length; i++) {
json.children.push(await this.toJSON(children[i], omit));
}
})());
},

children_meta: (node, json, promiseQueue) => {
promiseQueue.push(
this._metaDictToGuids(this.core.getChildrenMeta(node))
.then(children_meta => json.children_meta = children_meta)
);
}
}
};

Object.keys(json).forEach(key => {
if(exporters[key]) {
exporters[key](node, json, asyncTasks);
}
});

asyncTasks.push(
this._metaDictToGuids(this.core.getChildrenMeta(node))
.then(children_meta => json.children_meta = children_meta)
);
await Promise.all(asyncTasks);
return json;
}
Expand Down
39 changes: 39 additions & 0 deletions test/common/JSONImporter.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -1217,4 +1217,43 @@ describe('JSONImporter', function () {
assert(newNode);
});
});

describe('omits', function () {
before(async () => {
root = await getNewRootNode(core);
importer = new Importer(core, root);
const state = {attributes: {name: 'hello'}};
await importer.import(root, state);
});

it('should omit children in toJSON', async function () {
const json = await importer.toJSON(root, ['children']);
assert(json.children === undefined);
});

it('should omit pointers in toJSON', async function() {
const json = await importer.toJSON(root, 'pointers');
assert(json.pointers === undefined);
});

it('should omit sets and associated attributes in toJSON', async function() {
const json = await importer.toJSON(root, ['sets']);
['sets', 'member_attributes', 'member_registry'].forEach(attr => assert(json[attr] === undefined));
});

it('should omit only member_registry', async function() {
const json = await importer.toJSON(root, ['member_registry']);
assert(json.member_registry === undefined);
});

it('should omit only attributes', async function() {
const json = await importer.toJSON(root, ['attributes']);
assert(json.attributes === undefined);
});

it('should omit only attribute_meta', async function() {
const json = await importer.toJSON(root, ['attribute_meta']);
assert(json.attribute_meta === undefined);
});
});
});

0 comments on commit 420edf1

Please sign in to comment.