DenQ / list-to-tree

Convert list to tree
BSD 3-Clause "New" or "Revised" License
87 stars 30 forks source link

Consider dynamic parent/child matching fn() #22

Closed tremendus closed 1 year ago

tremendus commented 5 years ago

https://github.com/DenQ/list-to-tree/blob/06f51966783687eff82645b96de136a6a8bd2853/dist/list-to-tree.js#L39

I have a need to generate a tree from a collection (array of objects). But my paths are nested - eg:

{
  id: 100,
  field: 'val',
  // ... 
  meta: {
    parent: 'abc-123'
  }
}

I need to either pass dot-notation paths (and use a third party lib, like _ or object-path) or, to avoid dependencies, perhaps consider passing a matching fn to the constructor, which I can use third party libs without affecting deps on this module.

// list-to-tree constructor - add new param to end
 constructor(list, options = {}, matcher) {
    const _list = list.map((item) => item);

    options = Object.assign({}, defaultOptions, options);
    this.options = options;
    const { key_id, key_parent } = options;

    sortBy(_list, key_parent, key_id);
    const tree = new IronTree({ [key_id]: 0 });
    _list.forEach((item, index) => {
      tree.add((parentNode) => {
       // crude example below:
        return matcher ? matcher(item, key_id, parentNode, key_parent) : parentNode.get(key_id) === item[key_parent];
      }, item);
    });

    this.tree = tree;
  }

Then you could pass whatever id-to-id matching fns you need.

// my application code
const objectPath = require('object-path')
matcher = function (item, key_id, parentNode, key_parent) {
  return objectPath.get(parentNode, key_id) === objectPath.get(item, key_parent)
}

Now I can use:

new Tree(list, {
  key_id: 'id',
  key_parent: 'meta.parent'
}, matcher)

Thoughts?

DenQ commented 5 years ago

@tremendus good idea! I have a lot of work right now. I can do this next week. Or you can transform your list now.

...
{
  meta: {
    parent: 'abc-123'
  }
}

to

...
{
  parent: 'abs-123',
  meta: {
    parent: 'abc-123'
  }
}