npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

node-treeview

v1.5.0

Published

Asynchronous filesystem tree view for node

Downloads

16

Readme

node-treeview

Asynchronous filesystem tree view for node.

Build Status

Javascript (quick start)

Usage

const { TreeView } = require('node-treeview');

// Using callback
new TreeView(options).process(path, (error, tree) => {
  if (tree) {
    // do some stuff...
  } else {
    // handle error...
  }
});

// Using Promise
new TreeView(options).process(path).then(tree => {
  // do some stuff...
}).catch(error => {
  // handle error...
});

// Using async/await
async function getTree() {
  let tree;
  try {
    tree = await new TreeView(options).process(path);
  } catch (error) {
    // handle error...
  }
  // do some stuff...
}
getTree();

Example

const { TreeView } = require('node-treeview');

new TreeView({ content: true, depth: 2 })
  .process('path/to/dir')
  .then(tree => console.log(tree));

Here is what the json output looks like:

[{
  "name": "file1.txt",
  "path": "path/to/dir",
  "pathname": "path/to/dir/file1.txt",
  "depth": 0,
  "created": "2017-10-23T18:29:28.000Z",
  "modified": "2017-10-23T18:29:28.000Z",
  "type": "file",
  "size": 13,
  "ext": "txt",
  "binary": false,
  "content": "file1 content"
}, {
  "name": "subdir",
  "path": "path/to/dir",
  "pathname": "path/to/dir/subdir",
  "depth": 0,
  "created": "2017-10-22T10:48:48.000Z",
  "modified": "2017-10-23T18:29:29.000Z",
  "type": "dir",
  "nodes": [{
    "name": "file2.txt",
    "path": "path/to/dir/subdir",
    "pathname": "path/to/dir/subdir/file2.txt",
    "depth": 1,
    "created": "2017-10-23T18:29:28.000Z",
    "modified": "2017-10-23T18:29:29.000Z",
    "type": "file",
    "size": 13,
    "ext": "txt",
    "binary": false,
    "content": "file3 content"
  }, {
    "name": "logo.png",
    "path": "path/to/dir/subdir",
    "pathname": "path/to/dir/subdir/logo.png",
    "depth": 1,
    "created": "2017-10-23T18:29:29.000Z",
    "modified": "2017-10-23T18:29:29.000Z",
    "type": "file",
    "size": 325,
    "ext": "png",
    "binary": true,
    "content": "iVBORw0KGgoAAAANSUh..." //-> base64
  }]
}]

The TreeView lets you listen to item events.

const { TreeView } = require('node-treeview');

new TreeView()
  .on('item', data => console.log(`${data.type}: ${data.pathname}`))
  .process('path/to/dir')
  .then(() => console.log('done!'));

Here is what the txt output looks like:

file: path/to/dir/file1.txt
dir: path/to/dir/subdir
file: path/to/dir/subdir/file2.txt
file: path/to/dir/subdir/logo.png
done!

Emitted file never have content property, emitted dir always have nodes property equal to an empty array.

The TreeView lets you process trees in parallel.

const { TreeView } = require('node-treeview');

const treeView = new TreeView({
  relative: true
}).on('item', (data, ctx) => {
  // Listen to each emitted data in its own context
  // ('path/to/dir1' or 'path/to/dir2')
  console.log(`${ctx.rootPath} -> ${data.pathname}`);
});

Promise.all[
  // Use the same TreeView instance to process different
  // paths in parallel with the same options
  treeView.process('path/to/dir1'),
  treeView.process('path/to/dir2')
].then(([tree1, tree2]) => {
  console.log(tree1);
  console.log(tree2);
});

The TreeView lets you watch the filesystem.

const { TreeView } = require('node-treeview');

const treeView = new TreeView();

treeview
  .on('item'), (item) => {/* Item emitted (discovered, added, modified or removed) */})

  .on('ready'), (tree) => {/* Initial tree available */})

  .on('add'), (item) => {/* Item added */})
  .on('change'), (item) => {/* Item modified */})
  .on('unlink'), (item) => {/* Item removed */})

  .on('tree'), (tree) => {/* Refreshed tree available (after 'add', 'change' or 'unlink' event) */})

  .on('all'), (event, data) => {/* Listen to all events */});

// Start watching
const watcher = treeview.watch('path/to/dir');

// Stop watching after 1mn
setTimeout(watcher.close, 60000);

Under the hood, the watch feature is provided by fs.watch on Mac and Windows, and chokidar on other platforms.

You should NOT process trees in parallel when you watch the filesystem. Otherwise the watch method will not work properly.

TypeScript

Interface overview

// Basic interface of files and directories (used for unreadable resource)
export interface IRef {
  name: string;
  path: string;
  pathname: string;
  depth: number;
  error?: any;
}

export interface IFile extends IRef {
  type: 'file';
  created: Date;
  modified: Date;
  size: number;
  ext: string;
  binary: boolean;
  content?: string;
}

export interface IDir extends IRef {
  type: 'dir';
  created: Date;
  modified: Date;
  nodes: TreeNode[];
}

// The final output is of type: `TreeNode[]`
// and the `TreeView.process` method returns a `Promise<TreeNode[]>`
export type TreeNode = IFile | IDir | IRef;

// List of emitted events
export type Event
  = 'item'
  | 'ready'
  | 'tree'
  | 'add'
  | 'change'
  | 'unlink'
  | 'all';

Options

export interface IOptsParam {
  // Include hidden files in output
  all?: boolean;
  // Add files content to output
  content?: boolean;
  // Maximum depth of directories
  depth?: number;
  // Use relative path
  relative?: boolean;
  // List of directory paths to include in output
  include?: string[];
  // List of directory paths to exclude from output
  exclude?: string[];
  // Match files based on glob pattern
  glob?: string[];
  // Sort output
  sort?: Sorting;
}

// Tree sort type
export enum Sorting {
  Alpha,
  FileFirst,
  DirFirst
}

Using typing

import { TreeView } from 'node-treeview';
import * as Model from 'node-treeview/model'

const options: Model.IOptsParam = { depth: 2 };
const path = 'path/to/dir';

const promise: Promise<TreeNode[]> =
  new TreeView(options).process(path);

promise.then(tree => {
  tree.forEach(item => {
    if ((item as Model.IRef).error) {
      // handle error...
    } else if ((item as Model.IDir).type === 'dir') {
      // handle directory...
    } else if ((item as Model.IFile).type === 'file') {
      // handle file...
    }
  });
});

Helper

flatten

The flatten helper lets you get a flat version of the tree.

import { TreeView } from 'node-treeview';
import { flatten } from 'node-treeview/helper';

new TreeView().process('path/to/dir').then(tree => {
  const flat = flatten(tree);
  console.log(flat);
});

Or for JavaScript style using require:

const { TreeView } = require('node-treeview');
const { flatten } = require('node-treeview/helper');
// ...

Here is what the json output looks like:

[{
  "name": "file1.txt",
  "path": "path/to/dir",
  "pathname": "path/to/dir/file1.txt",
  "depth": 0,
  "created": "2017-10-23T18:29:28.000Z",
  "modified": "2017-10-23T18:29:28.000Z",
  "type": "file",
  "size": 13,
  "ext": "txt",
  "binary": false
}, {
  "name": "file2.txt",
  "path": "path/to/dir/subdir",
  "pathname": "path/to/dir/subdir/file2.txt",
  "depth": 1,
  "created": "2017-10-23T18:29:28.000Z",
  "modified": "2017-10-23T18:29:29.000Z",
  "type": "file",
  "size": 13,
  "ext": "txt",
  "binary": false
}, {
  "name": "logo.png",
  "path": "path/to/dir/subdir",
  "pathname": "path/to/dir/subdir/logo.png",
  "depth": 1,
  "created": "2017-10-23T18:29:29.000Z",
  "modified": "2017-10-23T18:29:29.000Z",
  "type": "file",
  "size": 325,
  "ext": "png",
  "binary": true
}]

clean

The clean helper lets you clean empty directories from the tree.

import { TreeView } from 'node-treeview';
import { clean } from 'node-treeview/helper';

new TreeView().process('path/to/dir').then(tree => {
  const cleaned = clean(tree);
  console.log(cleaned);
});

Or for JavaScript style using require:

const { TreeView } = require('node-treeview');
const { clean } = require('node-treeview/helper');
// ...

pretty

The pretty helper lets you pretty-print the tree.

import { TreeView } from 'node-treeview';
import { pretty } from 'node-treeview/helper';

new TreeView().process('path/to/dir').then(tree => {
  console.log(pretty(tree));
});

Here is what the txt output looks like:

├─ fruits
│  ├─ apple.txt
│  └─ pears.txt
└─ vegetables
   ├─ bean.txt
   ├─ potato.txt
   └─ endive.txt

With the pretty helper you have full control over how to render the tree.

import { TreeView } from 'node-treeview';
import { pretty } from 'node-treeview/helper';

new TreeView().process('path/to/dir').then(tree => {
  console.log(
    pretty(tree, (box: string, item: Model.TreeNode) => {
      if ((item as Model.IDir).type === 'dir') {
        return box + `(${item.name})`;
      } else if ((item as Model.IFile).type === 'file') {
        return box + item.name + ` [${(item as Model.IFile).size} bytes]`;
      } else {
        return box + item.name;
      }
    })
  );
});

Here is what the txt output looks like:

├─ (fruits)
│  ├─ apple.txt [51 bytes]
│  └─ pears.txt [24 bytes]
└─ (vegetables)
   ├─ bean.txt [13 bytes]
   ├─ potato.txt [87 bytes]
   └─ endive.txt [69 bytes]

And for quick rendering, use the predefined renderer functions.

import { TreeView } from 'node-treeview';
import { pretty } from 'node-treeview/helper';
import { renderer } from 'node-treeview/helper/pretty';

new TreeView().process('path/to/dir').then(tree => {
  console.log(pretty(tree, renderer.light));
  console.log(pretty(tree, renderer.dark));
});

Cli

node-treeview

Usage: node-treeview <path> [options]

Options:
  --version, -v   Show version number                                             [boolean]
  --help, -h      Show help                                                       [boolean]
  --all, -a       Include hidden files in output                                  [boolean]
  --content, -c   Add files content to output                                     [boolean]
  --depth, -d     Maximum depth of directories                       [number] [default: -1]
  --relative, -r  Use relative path                                               [boolean]
  --include, -i   List of directory paths to include in output                      [array]
  --exclude, -e   List of directory paths to exclude from output                    [array]
  --glob, -g      Match files based on glob pattern                                 [array]
  --sort, -s      Sort output 0 (Alpha), 1 (FileFirst), 2 (DirFirst)  [number] [default: 0]
  --clean, -n     Clean empty directories from output                             [boolean]
  --flatten, -f   Flatten output                                                  [boolean]
  --pretty, -p    Pretty-print output                                              [string]
  --watch, -w     Watch filesystem                                                [boolean]
  --output, -o    Output file path                                                 [string]
  --debug         Add debugging information to output                             [boolean]

Contribute

git clone https://github.com/avine/node-treeview.git
cd ./node-treeview
npm install
npm run all # npm run clean && npm run build && npm test

License

MIT @ Avine