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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.