2

I have this object:

const sampleObj = { 
  home: true,
  products_edit: true,
  products_create: true,
  orders_delete: true,
  pages_category_create: true
}

I want to convert the above object to:

const result = {
    home: {
    status: 'full'
  },
  products: {
    status: 'limited',
    subOptions: {
      edit: true,
      create: true
    }
  },
  orders: {
    status: 'limited',
    subOptions: {
      delete: true,
    }
  },
  pages: {
    status: 'limited',
    subOptions: {
      category: {
        status: 'limited',
        subOptions: {
          create: true,
        }
      },
    }
  }
}

So I want to convert the object keys to nested objects based on _ character and the _ parts could be more than 3.

If the key is one part like "Home" the status should be "full", otherwise it should be "limited".

This is my current code:

function rolesFlattener(obj) {
  let final = {};
  Object.keys(obj).forEach((item, index) => {
    const path = item.split('_');
    if(path.length > 1) {
      path.reduce((prev, current, i, array) => {
        if(!final[prev]) {
          final[prev] = {
            status: 'limited',
            subOptions: {}
          }
        }
        final[prev].subOptions[current] = true;

      return current;
      });
    }
    else {
      final[path[0]] = {
        status: 'full'
      } 
    }
  })
  console.log(final)
}

// userRole: {
  //   home: {
  //     status: 'full'
  //   },
  //   products: {
  //     status: 'limited',
  //     subOptions: {
  //       edit: true,
  //       create: true
  //     }
  //   },
  //   orders: {
  //     status: 'limited',
  //     subOptions: {
  //       delete: true,
  //     }
  //   },
  //   pages: {
  //     status: 'limited',
  //     subOptions: {
  //       category: {
  //         status: 'limited',
  //         subOptions: {
  //           create: true,
  //         }
  //       },
  //     }
  //   }
  // }

let sampleObj = { 
  home: true,
  products_edit: true,
  products_create: true,
  orders_delete: true,
  pages_category_create: true
}

rolesFlattener(sampleObj)

4
  • @NinaScholz this is my draft repl.it/@Mohammad_RezaR5/nested I can't handle the second part in pages Commented Jan 5, 2019 at 17:13
  • why is home an object, not a final property like the other last keys? Commented Jan 5, 2019 at 17:24
  • I'm sure someone will eventually do this for you, but is there a specific problem that you are having with your implementation? It appears as if you understand the domain of the problem well. Commented Jan 5, 2019 at 17:29
  • @NinaScholz Because home is one part and it doesn't need to be split. Commented Jan 5, 2019 at 17:30

2 Answers 2

3

You could take an empty path as special case take { status: 'full' } as new value.

Then reduce the keys and assign a default new object, if not exist and return subOptions for each loop.

Finally assign the value.

function setValue(object, path, value) {
    var last = path.pop();

    if (!path.length) {
        value = { status: 'full' };
    }

    path.reduce(
        (o, k) => (o[k] = o[k] || { status: 'limited', subOptions: {} }).subOptions,
        object
    )[last] = value;
}

const
    values = { home: true, financials: true, products_edit: true, products_create: true, orders_delete: true, pages_category_create: true },
    result = {};

Object.entries(values).forEach(([k, v]) => setValue(result, k.split('_'), v));

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Sign up to request clarification or add additional context in comments.

1 Comment

thanks it's good but home is not static... I changed your code a little bit: repl.it/@Mohammad_RezaR5/nested
1

This is how I would do it, probably could be optimized.

Combination of Object.keys and Array#reduce.

const sampleObj = { 
  home: true,
  products_edit: true,
  products_create: true,
  orders_delete: true,
  pages_category_create: true
}

const res = Object.keys(sampleObj).reduce((acc,cur)=>{
  const value = sampleObj[cur];
  const tree  = cur.split("_");
  const root  = tree.shift();
  
  if(!acc[root]){
    acc[root] = {};
    if(tree.length === 0){
       acc[root].status = "full"
       return acc;
    } else {
       acc[root].subOptions = {};
       acc[root].status = "limited";
    }
  }
  
  acc[root].subOptions[tree.shift()] = tree.reverse().reduce((acc,cur)=>{
      return {[cur]:acc}
  }, value);
  return acc;
  
}, {});

console.log(res);

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.