JSFiddle - React, Tailwind, and code Playground

by Oliver Caldwell

HTML

<script src="https://rawgit.com/lodash/lodash/3.9.3/lodash.js"></script>

JavaScript

var input = [
    {
        name: 'foo',
        url: '/somewhere1',
        templateUrl: 'foo.tpl.html',
        title: 'title A',
        subtitle: 'description A'
    },
    {
        name: 'foo.bar',
        url: '/somewhere2',
        templateUrl: 'anotherpage.tpl.html',
        title: 'title B',
        subtitle: 'description B'
    },
    {
        name: 'buzz.fizz',
        url: '/another/place',
        templateUrl: 'hello.tpl.html',  
        title: 'title C',  
        subtitle: 'description C'
    },
    {
        name: 'foo.hello.world',
        url: '/',
        templateUrl: 'world.tpl.html',
        title: 'title D',  
        subtitle: 'description D'
    }
];

function formatRoute(route) {
    return _.merge(_.pick(route, ['url', 'templateUrl']), {
        name: route.name.split('.'),
        data: _.pick(route, ['title', 'subtitle']),
        children: []
    });
}

function getNameLength(route) {
    return route.name.length;
}

function buildTree(tree, route) {
    var path = _.slice(route.name, 0, -1);
    
    insertAtPath(tree, path, _.merge({}, route, {
        name: _.last(route.name)
    }));
    
    return tree;
}

function insertAtPath(children, path, route) {
    var head = _.first(path);
    
    var match = _.find(children, function (child) {
        return child.name === head;
    });
    
    if (path.length === 0) {
        children.push(route);
    }
    else {
        if (!match) {
            match = {
                name: head,
                data: {},
                children: []
            };
            children.push(match);
        }
        
        insertAtPath(match.children, _.rest(path), route);
    }
}


// Map the routes into their correct formats.
var routes = _.sortBy(_.map(input, formatRoute), getNameLength);

// Now we can reduce this well formatted array into the desired format.
var out = _.reduce(routes, buildTree, []);

console.log(out);