'Getting File Directories as nested Array object

I want to get my file directories as nested array object but i can't seem to figure out how to convert

[
  'routes/files',
  'routes/files/emptyfolder',
  'routes/files/somefolder',
  'routes/files/somefolder/example.docx',
  'routes/files/test.docx',
  'routes/randomdata.json'
]

to

[
    {
      title: 'routes',
      content: [
        {
          title: 'files',
          content: [
            {
                title: 'empty folder',
                content: []
            },
            {
                title: 'somefolder',
                content: [
                    {
                        title: 'example.docx',
                    },
                ]
            },
            {
                title: 'test.docx',
            }
          ],
        },
        {
            title: 'randomdata.json'
        }
    ],
}
]

it looks impossible problem for me to solve. I would love to know how to solve it.

Thank you.



Solution 1:[1]

Here is how I solved it: Not the best solution, but works.

const arr = [
  "routes/files",
  "routes/files/emptyfolder",
  "routes/files/somefolder",
  "routes/files/somefolder/example.docx",
  "routes/files/test.docx",
  "routes/randomdata.json",
];

const arr2 = arr.map((p) => p.split("/"));

const setNestedObjectField = (
  obj,
  props,
  value
) => {
  if (!Array.isArray(obj)) {
    if (!obj.content) {
      obj.content = [];
    }
    obj = obj.content;
  }
  for (const propName of props) {
    const next = obj.find((el) => el.title === propName);
    if (!next) {
      console.assert(props.at(-1) === propName);
      // last propName
      obj.push(value);
    } else {
      if (!next.content) {
        next.content = [];
      }
      obj = next.content;
    }
  }
};

const rez = [];
let index = 0;
while (arr2.some((s) => s[index] !== undefined)) {
  // arr2 = arr2.filter((a) => a.length);
  const layer = arr2.reduce((acc, pathArr) => {
    if (pathArr[index] === undefined) return acc;
    acc.add(pathArr.slice(0, index + 1).join("/"));
    return acc;
  }, new Set());

  // console.log({ layer });

  for (const key of layer) {
    setNestedObjectField(rez, key.split("/"), { title: key.split("/").at(-1) });
  }
  index++;
}

console.log(rez);

Solution 2:[2]

I came across this question and it's an interesting problem, I know it's already been answered, but I wanted to spend a little of my time to solve it my way.

here I leave my code:

function nestedDirectories (arr) {
  const splittedArray = arr.map(a => a.split('/'));
  return {
    mergeObjs: function(target, source) {
      for (let key in source) {
        if(!target[key]) target[key] = {};
        target[key] = this.mergeObjs(target[key], source[key]);
      }
      return target;
    },
    buildResponse: function (objMain) {
      let arr = [];
      for (let key in objMain) {
        let o = { title: key, content: [] };
        if(key.includes(".")) {
          delete o.content;
        } else if (Object.keys(objMain[key]).length) {
          o.content = this.buildResponse(objMain[key]);
        }
        arr.push(o);
      }
      return arr;
    },
    exec: function () {
      let targetObject = {};
      splittedArray.forEach(arrParent => {
        let strObj = '';
        for (let i = arrParent.length - 1; i >= 0 ; i--) {
          strObj = `"${arrParent[i]}": {${strObj}}`;
        }
        let parseObj = JSON.parse(`{${strObj}}`);
        targetObject = this.mergeObjs(targetObject, parseObj);
      });
      return this.buildResponse(targetObject);
    }
  }
}

and use it like this:

const dirs = [
  'routes/files',
  'routes/files/emptyfolder',
  'routes/files/somefolder',
  'routes/files/test.docx',
  'routes/randomdata.json',
  'routes/files/somefolder/example.docx'
];

const data = nestedDirectories(dirs).exec();

result:

[
  {
    title: 'routes',
    content: [
      {
        title: 'files',
        content: [
          { title: 'emptyfolder', content: [] },
          {
            title: 'somefolder',
            content: [ { title: 'example.docx' } ]
          },
          { title: 'test.docx' }
        ]
      },
      { title: 'randomdata.json' }
    ]
  }
]

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 valerii15298
Solution 2 Nelsongt77