{"id":18522916,"url":"https://github.com/avine/node-treeview","last_synced_at":"2026-03-14T13:42:04.920Z","repository":{"id":120340079,"uuid":"107885207","full_name":"avine/node-treeview","owner":"avine","description":"Asynchronous filesystem tree view for node","archived":false,"fork":false,"pushed_at":"2018-07-01T23:27:28.000Z","size":594,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-24T05:13:17.626Z","etag":null,"topics":["asynchronous","command-line","filesystem","glob","json","node","terminal","tree","treeview","typescript","watch"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/avine.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-10-22T16:58:42.000Z","updated_at":"2019-03-27T21:18:58.000Z","dependencies_parsed_at":"2023-05-22T23:45:46.261Z","dependency_job_id":null,"html_url":"https://github.com/avine/node-treeview","commit_stats":{"total_commits":191,"total_committers":1,"mean_commits":191.0,"dds":0.0,"last_synced_commit":"cb5183a6a6a5951ee225dea1c444c7856bb33ef7"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/avine%2Fnode-treeview","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/avine%2Fnode-treeview/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/avine%2Fnode-treeview/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/avine%2Fnode-treeview/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/avine","download_url":"https://codeload.github.com/avine/node-treeview/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247888556,"owners_count":21013001,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["asynchronous","command-line","filesystem","glob","json","node","terminal","tree","treeview","typescript","watch"],"created_at":"2024-11-06T17:33:32.069Z","updated_at":"2026-03-14T13:42:04.913Z","avatar_url":"https://github.com/avine.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# node-treeview\n\nAsynchronous filesystem tree view for node.\n\n[![Build Status](https://travis-ci.org/avine/node-treeview.svg?branch=master)](https://travis-ci.org/avine/node-treeview)\n\n## Javascript (quick start)\n\n### Usage\n\n```js\nconst { TreeView } = require('node-treeview');\n\n// Using callback\nnew TreeView(options).process(path, (error, tree) =\u003e {\n  if (tree) {\n    // do some stuff...\n  } else {\n    // handle error...\n  }\n});\n\n// Using Promise\nnew TreeView(options).process(path).then(tree =\u003e {\n  // do some stuff...\n}).catch(error =\u003e {\n  // handle error...\n});\n\n// Using async/await\nasync function getTree() {\n  let tree;\n  try {\n    tree = await new TreeView(options).process(path);\n  } catch (error) {\n    // handle error...\n  }\n  // do some stuff...\n}\ngetTree();\n```\n\n### Example\n\n```js\nconst { TreeView } = require('node-treeview');\n\nnew TreeView({ content: true, depth: 2 })\n  .process('path/to/dir')\n  .then(tree =\u003e console.log(tree));\n```\n\nHere is what the `json` output looks like:\n\n```json\n[{\n  \"name\": \"file1.txt\",\n  \"path\": \"path/to/dir\",\n  \"pathname\": \"path/to/dir/file1.txt\",\n  \"depth\": 0,\n  \"created\": \"2017-10-23T18:29:28.000Z\",\n  \"modified\": \"2017-10-23T18:29:28.000Z\",\n  \"type\": \"file\",\n  \"size\": 13,\n  \"ext\": \"txt\",\n  \"binary\": false,\n  \"content\": \"file1 content\"\n}, {\n  \"name\": \"subdir\",\n  \"path\": \"path/to/dir\",\n  \"pathname\": \"path/to/dir/subdir\",\n  \"depth\": 0,\n  \"created\": \"2017-10-22T10:48:48.000Z\",\n  \"modified\": \"2017-10-23T18:29:29.000Z\",\n  \"type\": \"dir\",\n  \"nodes\": [{\n    \"name\": \"file2.txt\",\n    \"path\": \"path/to/dir/subdir\",\n    \"pathname\": \"path/to/dir/subdir/file2.txt\",\n    \"depth\": 1,\n    \"created\": \"2017-10-23T18:29:28.000Z\",\n    \"modified\": \"2017-10-23T18:29:29.000Z\",\n    \"type\": \"file\",\n    \"size\": 13,\n    \"ext\": \"txt\",\n    \"binary\": false,\n    \"content\": \"file3 content\"\n  }, {\n    \"name\": \"logo.png\",\n    \"path\": \"path/to/dir/subdir\",\n    \"pathname\": \"path/to/dir/subdir/logo.png\",\n    \"depth\": 1,\n    \"created\": \"2017-10-23T18:29:29.000Z\",\n    \"modified\": \"2017-10-23T18:29:29.000Z\",\n    \"type\": \"file\",\n    \"size\": 325,\n    \"ext\": \"png\",\n    \"binary\": true,\n    \"content\": \"iVBORw0KGgoAAAANSUh...\" //-\u003e base64\n  }]\n}]\n```\n\nThe `TreeView` lets you listen to `item` events.\n\n```js\nconst { TreeView } = require('node-treeview');\n\nnew TreeView()\n  .on('item', data =\u003e console.log(`${data.type}: ${data.pathname}`))\n  .process('path/to/dir')\n  .then(() =\u003e console.log('done!'));\n```\n\nHere is what the `txt` output looks like:\n\n```txt\nfile: path/to/dir/file1.txt\ndir: path/to/dir/subdir\nfile: path/to/dir/subdir/file2.txt\nfile: path/to/dir/subdir/logo.png\ndone!\n```\n\n\u003e Emitted file never have `content` property,\nemitted dir always have `nodes` property equal to an empty array.\n\nThe `TreeView` lets you process trees in parallel.\n\n```js\nconst { TreeView } = require('node-treeview');\n\nconst treeView = new TreeView({\n  relative: true\n}).on('item', (data, ctx) =\u003e {\n  // Listen to each emitted data in its own context\n  // ('path/to/dir1' or 'path/to/dir2')\n  console.log(`${ctx.rootPath} -\u003e ${data.pathname}`);\n});\n\nPromise.all[\n  // Use the same TreeView instance to process different\n  // paths in parallel with the same options\n  treeView.process('path/to/dir1'),\n  treeView.process('path/to/dir2')\n].then(([tree1, tree2]) =\u003e {\n  console.log(tree1);\n  console.log(tree2);\n});\n```\n\nThe `TreeView` lets you watch the filesystem.\n\n```js\nconst { TreeView } = require('node-treeview');\n\nconst treeView = new TreeView();\n\ntreeview\n  .on('item'), (item) =\u003e {/* Item emitted (discovered, added, modified or removed) */})\n\n  .on('ready'), (tree) =\u003e {/* Initial tree available */})\n\n  .on('add'), (item) =\u003e {/* Item added */})\n  .on('change'), (item) =\u003e {/* Item modified */})\n  .on('unlink'), (item) =\u003e {/* Item removed */})\n\n  .on('tree'), (tree) =\u003e {/* Refreshed tree available (after 'add', 'change' or 'unlink' event) */})\n\n  .on('all'), (event, data) =\u003e {/* Listen to all events */});\n\n// Start watching\nconst watcher = treeview.watch('path/to/dir');\n\n// Stop watching after 1mn\nsetTimeout(watcher.close, 60000);\n```\n\nUnder the hood, the `watch` feature is provided by `fs.watch` on Mac and Windows, and `chokidar` on other platforms.\n\n\u003e You should NOT process trees in parallel when you watch the filesystem.\nOtherwise the `watch` method will not work properly.\n\n## TypeScript\n\n### Interface overview\n\n```ts\n// Basic interface of files and directories (used for unreadable resource)\nexport interface IRef {\n  name: string;\n  path: string;\n  pathname: string;\n  depth: number;\n  error?: any;\n}\n\nexport interface IFile extends IRef {\n  type: 'file';\n  created: Date;\n  modified: Date;\n  size: number;\n  ext: string;\n  binary: boolean;\n  content?: string;\n}\n\nexport interface IDir extends IRef {\n  type: 'dir';\n  created: Date;\n  modified: Date;\n  nodes: TreeNode[];\n}\n\n// The final output is of type: `TreeNode[]`\n// and the `TreeView.process` method returns a `Promise\u003cTreeNode[]\u003e`\nexport type TreeNode = IFile | IDir | IRef;\n\n// List of emitted events\nexport type Event\n  = 'item'\n  | 'ready'\n  | 'tree'\n  | 'add'\n  | 'change'\n  | 'unlink'\n  | 'all';\n```\n\n### Options\n\n```ts\nexport interface IOptsParam {\n  // Include hidden files in output\n  all?: boolean;\n  // Add files content to output\n  content?: boolean;\n  // Maximum depth of directories\n  depth?: number;\n  // Use relative path\n  relative?: boolean;\n  // List of directory paths to include in output\n  include?: string[];\n  // List of directory paths to exclude from output\n  exclude?: string[];\n  // Match files based on glob pattern\n  glob?: string[];\n  // Sort output\n  sort?: Sorting;\n}\n\n// Tree sort type\nexport enum Sorting {\n  Alpha,\n  FileFirst,\n  DirFirst\n}\n```\n\n### Using typing\n\n```ts\nimport { TreeView } from 'node-treeview';\nimport * as Model from 'node-treeview/model'\n\nconst options: Model.IOptsParam = { depth: 2 };\nconst path = 'path/to/dir';\n\nconst promise: Promise\u003cTreeNode[]\u003e =\n  new TreeView(options).process(path);\n\npromise.then(tree =\u003e {\n  tree.forEach(item =\u003e {\n    if ((item as Model.IRef).error) {\n      // handle error...\n    } else if ((item as Model.IDir).type === 'dir') {\n      // handle directory...\n    } else if ((item as Model.IFile).type === 'file') {\n      // handle file...\n    }\n  });\n});\n```\n\n## Helper\n\n### flatten\n\nThe `flatten` helper lets you get a flat version of the tree.\n\n```ts\nimport { TreeView } from 'node-treeview';\nimport { flatten } from 'node-treeview/helper';\n\nnew TreeView().process('path/to/dir').then(tree =\u003e {\n  const flat = flatten(tree);\n  console.log(flat);\n});\n```\n\nOr for JavaScript style using `require`:\n\n```js\nconst { TreeView } = require('node-treeview');\nconst { flatten } = require('node-treeview/helper');\n// ...\n```\n\nHere is what the `json` output looks like:\n\n```json\n[{\n  \"name\": \"file1.txt\",\n  \"path\": \"path/to/dir\",\n  \"pathname\": \"path/to/dir/file1.txt\",\n  \"depth\": 0,\n  \"created\": \"2017-10-23T18:29:28.000Z\",\n  \"modified\": \"2017-10-23T18:29:28.000Z\",\n  \"type\": \"file\",\n  \"size\": 13,\n  \"ext\": \"txt\",\n  \"binary\": false\n}, {\n  \"name\": \"file2.txt\",\n  \"path\": \"path/to/dir/subdir\",\n  \"pathname\": \"path/to/dir/subdir/file2.txt\",\n  \"depth\": 1,\n  \"created\": \"2017-10-23T18:29:28.000Z\",\n  \"modified\": \"2017-10-23T18:29:29.000Z\",\n  \"type\": \"file\",\n  \"size\": 13,\n  \"ext\": \"txt\",\n  \"binary\": false\n}, {\n  \"name\": \"logo.png\",\n  \"path\": \"path/to/dir/subdir\",\n  \"pathname\": \"path/to/dir/subdir/logo.png\",\n  \"depth\": 1,\n  \"created\": \"2017-10-23T18:29:29.000Z\",\n  \"modified\": \"2017-10-23T18:29:29.000Z\",\n  \"type\": \"file\",\n  \"size\": 325,\n  \"ext\": \"png\",\n  \"binary\": true\n}]\n```\n\n### clean\n\nThe `clean` helper lets you clean empty directories from the tree.\n\n```ts\nimport { TreeView } from 'node-treeview';\nimport { clean } from 'node-treeview/helper';\n\nnew TreeView().process('path/to/dir').then(tree =\u003e {\n  const cleaned = clean(tree);\n  console.log(cleaned);\n});\n```\n\nOr for JavaScript style using `require`:\n\n```js\nconst { TreeView } = require('node-treeview');\nconst { clean } = require('node-treeview/helper');\n// ...\n```\n\n### pretty\n\nThe `pretty` helper lets you pretty-print the tree.\n\n```ts\nimport { TreeView } from 'node-treeview';\nimport { pretty } from 'node-treeview/helper';\n\nnew TreeView().process('path/to/dir').then(tree =\u003e {\n  console.log(pretty(tree));\n});\n```\n\nHere is what the `txt` output looks like:\n\n```txt\n├─ fruits\n│  ├─ apple.txt\n│  └─ pears.txt\n└─ vegetables\n   ├─ bean.txt\n   ├─ potato.txt\n   └─ endive.txt\n```\n\nWith the `pretty` helper you have full control over how to render the tree.\n\n```ts\nimport { TreeView } from 'node-treeview';\nimport { pretty } from 'node-treeview/helper';\n\nnew TreeView().process('path/to/dir').then(tree =\u003e {\n  console.log(\n    pretty(tree, (box: string, item: Model.TreeNode) =\u003e {\n      if ((item as Model.IDir).type === 'dir') {\n        return box + `(${item.name})`;\n      } else if ((item as Model.IFile).type === 'file') {\n        return box + item.name + ` [${(item as Model.IFile).size} bytes]`;\n      } else {\n        return box + item.name;\n      }\n    })\n  );\n});\n```\n\nHere is what the `txt` output looks like:\n\n```txt\n├─ (fruits)\n│  ├─ apple.txt [51 bytes]\n│  └─ pears.txt [24 bytes]\n└─ (vegetables)\n   ├─ bean.txt [13 bytes]\n   ├─ potato.txt [87 bytes]\n   └─ endive.txt [69 bytes]\n```\n\nAnd for quick rendering, use the predefined `renderer` functions.\n\n```ts\nimport { TreeView } from 'node-treeview';\nimport { pretty } from 'node-treeview/helper';\nimport { renderer } from 'node-treeview/helper/pretty';\n\nnew TreeView().process('path/to/dir').then(tree =\u003e {\n  console.log(pretty(tree, renderer.light));\n  console.log(pretty(tree, renderer.dark));\n});\n```\n\n## Cli\n\n```txt\nnode-treeview\n\nUsage: node-treeview \u003cpath\u003e [options]\n\nOptions:\n  --version, -v   Show version number                                             [boolean]\n  --help, -h      Show help                                                       [boolean]\n  --all, -a       Include hidden files in output                                  [boolean]\n  --content, -c   Add files content to output                                     [boolean]\n  --depth, -d     Maximum depth of directories                       [number] [default: -1]\n  --relative, -r  Use relative path                                               [boolean]\n  --include, -i   List of directory paths to include in output                      [array]\n  --exclude, -e   List of directory paths to exclude from output                    [array]\n  --glob, -g      Match files based on glob pattern                                 [array]\n  --sort, -s      Sort output 0 (Alpha), 1 (FileFirst), 2 (DirFirst)  [number] [default: 0]\n  --clean, -n     Clean empty directories from output                             [boolean]\n  --flatten, -f   Flatten output                                                  [boolean]\n  --pretty, -p    Pretty-print output                                              [string]\n  --watch, -w     Watch filesystem                                                [boolean]\n  --output, -o    Output file path                                                 [string]\n  --debug         Add debugging information to output                             [boolean]\n```\n\n## Contribute\n\n```bash\ngit clone https://github.com/avine/node-treeview.git\ncd ./node-treeview\nnpm install\nnpm run all # npm run clean \u0026\u0026 npm run build \u0026\u0026 npm test\n```\n\n## License\n\nMIT @ [Avine](https://avine.io)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Favine%2Fnode-treeview","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Favine%2Fnode-treeview","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Favine%2Fnode-treeview/lists"}