├── .gitignore ├── .travis.yml ├── package.json ├── index.js ├── README.md └── test.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | coverage/ -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "5.4" 4 | - "4.2" 5 | - "4.0" 6 | - "0.12" 7 | - "0.11" 8 | - "0.10" 9 | - "0.8" 10 | - "0.6" 11 | - "iojs" 12 | sudo: false 13 | script: "npm run test" -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "list-to-tree-lite", 3 | "version": "0.1.0", 4 | "description": "convert list to tree-list", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "node test.js" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/William17/list-to-tree-lite.git" 12 | }, 13 | "keywords": [ 14 | "list", 15 | "to", 16 | "tree" 17 | ], 18 | "author": { 19 | "name": "William Leung", 20 | "email": "superbill2012@qq.com", 21 | "url": "https://github.com/William17" 22 | }, 23 | "license": "MIT", 24 | "bugs": { 25 | "url": "https://github.com/William17/list-to-tree-lite/issues" 26 | }, 27 | "homepage": "https://github.com/William17/list-to-tree-lite#readme" 28 | } 29 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | (function (root, factory) { 2 | if (typeof define === 'function' && define.amd) { 3 | define([], factory); 4 | } else if (typeof module === 'object' && module.exports) { 5 | module.exports = factory(); 6 | } else { 7 | root.listToTree = factory(); 8 | } 9 | }(this, function () { 10 | 'use strict'; 11 | return function listToTree(data, options) { 12 | options = options || {}; 13 | var ID_KEY = options.idKey || 'id'; 14 | var PARENT_KEY = options.parentKey || 'parent'; 15 | var CHILDREN_KEY = options.childrenKey || 'children'; 16 | 17 | var tree = [], childrenOf = {}; 18 | var item, id, parentId; 19 | 20 | for(var i = 0, length = data.length; i < length; i++) { 21 | item = data[i]; 22 | id = item[ID_KEY]; 23 | parentId = item[PARENT_KEY] || 0; 24 | // every item may have children 25 | childrenOf[id] = childrenOf[id] || []; 26 | // init its children 27 | item[CHILDREN_KEY] = childrenOf[id]; 28 | if (parentId != 0) { 29 | // init its parent's children object 30 | childrenOf[parentId] = childrenOf[parentId] || []; 31 | // push it into its parent's children object 32 | childrenOf[parentId].push(item); 33 | } else { 34 | tree.push(item); 35 | } 36 | }; 37 | 38 | return tree; 39 | } 40 | })); -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/William17/list-to-tree-lite.png?branch=master)](http://travis-ci.org/William17/list-to-tree-lite) 2 | # list-to-tree-lite 3 | A simple function converts a flat-list of objects with `id`, `parent` and `children` to a tree-list of objects. 4 | without any dependencies. 5 | ``` 6 | [{ 7 | id: 6, 8 | any: 'opps' 9 | }, { 10 | id: 2, 11 | parent: 5, 12 | any: 'foo', 13 | }, { 14 | id: 1, 15 | parent: 2, 16 | any: 'bar' 17 | }, { 18 | id: 5, 19 | any: 'hello' 20 | }, { 21 | id: 3, 22 | parent: 2, 23 | any: 'other' 24 | }] 25 | 26 | ``` 27 | to 28 | ``` 29 | [{ 30 | id: 6, 31 | any: 'opps', 32 | children: [] 33 | }, { 34 | id: 5, 35 | any: 'hello', 36 | children: [{ 37 | id: 2, 38 | parent: 5, 39 | any: 'foo', 40 | children: [{ 41 | id: 1, 42 | parent: 2, 43 | any: 'bar', 44 | children: [] 45 | }, { 46 | id: 3, 47 | parent: 2, 48 | any: 'other', 49 | children: [] 50 | }] 51 | }] 52 | }] 53 | 54 | ``` 55 | 56 | #Usage 57 | `listToTree(list[, options])` 58 | 59 | `options.idKey` 60 | the _id key_ of the item object, default `id` 61 | 62 | `options.parentKey` 63 | the _parent key_ of the item object, default `parent` 64 | 65 | `options.childrenKey` 66 | the _children key_ of the item object, default `children` 67 | 68 | #Install 69 | `npm install list-to-tree-lite --save` 70 | 71 | #Test 72 | `npm run test` 73 | 74 | #License 75 | MIT:http://william17.mit-license.org 76 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | 3 | var listToTree = require('./index'); 4 | var idKey = 'k' + Math.random().toString().substr(-5); 5 | var parentKey = 'p' + Math.random().toString().substr(-5); 6 | var childrenKey = 'c' + Math.random().toString().substr(-5); 7 | 8 | function genTree(itemCount, options) { 9 | var options = options || {}; 10 | var idKey = options.idKey || 'id'; 11 | var parentKey = options.parentKey || 'parent'; 12 | var childrenKey = options.childrenKey || 'children'; 13 | 14 | // unique id 15 | var ids = {}; 16 | function getId() { 17 | var id = 'id' + Math.random().toString().substr(-5); 18 | return ids[id] ? getId() : (ids[id]=id); 19 | } 20 | 21 | function gen(count, prev, parent, top) { 22 | 23 | if(count>=itemCount) { 24 | return top[childrenKey]; 25 | } 26 | 27 | var item = {}; 28 | item[idKey] = getId(); 29 | item[childrenKey] = []; 30 | 31 | // first child 32 | if (!count) { 33 | top = top || {}; 34 | top[idKey] = 0; 35 | top[childrenKey] = []; 36 | top[childrenKey].push(item); 37 | parent = top; 38 | } else if (Math.random() > 0.5) { 39 | parent[childrenKey].push(item); 40 | } else { 41 | prev[childrenKey].push(item); 42 | parent = prev; 43 | } 44 | item[parentKey] = parent[idKey]; 45 | return gen(++count, item, parent, top); 46 | } 47 | 48 | return gen(0); 49 | } 50 | 51 | function flattern(tree, options) { 52 | options = options || {}; 53 | var idKey = options.idKey || 'id'; 54 | var parentKey = options.parentKey || 'parent'; 55 | var childrenKey = options.childrenKey || 'children'; 56 | 57 | function fla(tree) { 58 | var list = [], children; 59 | for (var i = 0, length = tree.length; i < length; i++) { 60 | list = list.concat(tree[i]); 61 | if (tree[i][childrenKey] && tree[i][childrenKey].length > 0) { 62 | list = list.concat(fla(tree[i][childrenKey])); 63 | tree[i][childrenKey] = []; 64 | } 65 | } 66 | return list; 67 | } 68 | 69 | return fla(tree); 70 | } 71 | 72 | 73 | function testRandomTree() { 74 | var keys = { 75 | idKey: idKey, 76 | parentKey: parentKey, 77 | childrenKey: childrenKey 78 | } 79 | var originTree = genTree(10, keys); 80 | var list = flattern(JSON.parse(JSON.stringify(originTree)), keys); 81 | var tree = listToTree(JSON.parse(JSON.stringify(list)), keys); 82 | 83 | assert.deepEqual(originTree, tree); 84 | return true; 85 | } 86 | 87 | 88 | function testCustomTree() { 89 | var list = [{ 90 | id: 6, 91 | any: 'opps' 92 | }, { 93 | id: 2, 94 | parent: 5, 95 | any: 'foo', 96 | }, { 97 | id: 1, 98 | parent: 2, 99 | any: 'bar' 100 | }, { 101 | id: 5, 102 | any: 'hello' 103 | }, { 104 | id: 3, 105 | parent: 2, 106 | any: 'other' 107 | }]; 108 | 109 | var tree = [{ 110 | id: 6, 111 | any: 'opps', 112 | children: [] 113 | }, { 114 | id: 5, 115 | any: 'hello', 116 | children: [{ 117 | id: 2, 118 | parent: 5, 119 | any: 'foo', 120 | children: [{ 121 | id: 1, 122 | parent: 2, 123 | any: 'bar', 124 | children: [] 125 | }, { 126 | id: 3, 127 | parent: 2, 128 | any: 'other', 129 | children: [] 130 | }] 131 | }] 132 | }]; 133 | assert.deepEqual(listToTree(list), tree); 134 | return true; 135 | } 136 | 137 | assert.ok(testRandomTree()); 138 | assert.ok(testCustomTree()); 139 | 140 | 141 | console.log('✓ passed'); --------------------------------------------------------------------------------