Socket
Socket
Sign inDemoInstall

dree

Package Overview
Dependencies
Maintainers
1
Versions
132
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

dree - npm Package Compare versions

Comparing version 1.2.2 to 2.0.0

.travis.yml

149

lib/index.d.ts

@@ -29,2 +29,5 @@ declare type HexBase64Latin1Encoding = "latin1" | "hex" | "base64";

}
/**
* Enum whose values are DIRECTORY or FILE
*/
export declare enum Type {

@@ -34,30 +37,158 @@ DIRECTORY = "directory",

}
/**
* Interface of an object representing a Directory Tree
*/
export interface Dree {
/**
* The name of the node as a string
*/
name: string;
/**
* The absolute path of the node
*/
path: string;
/**
* The relative path from the root of the node
*/
relativePath: string;
/**
* Values: Type.DIRECTORY or Type.FILE
*/
type: Type;
/**
* A boolean with true value if the node is a symbolic link
*/
isSymbolicLink: boolean;
/**
* Optional. The size in bytes of the node
*/
sizeInBytes?: number;
/**
* Optional. The size of the node, rounded to two decimals and appropriate unit
*/
size?: string;
/**
* Optional. The hash of the node
*/
hash?: string;
/**
* Optional. The extension (without dot) of the node. Returned only if the node is a file
*/
extension?: string;
/**
* Optional. The fs.lstat or fs.fstat of the node
*/
stat?: Stats;
/**
* Optional. An array of Dree objects, containing all the children of the node
*/
children?: Dree[];
}
export interface Options {
/**
* Interface of the options object used with "scan" function
*/
export interface ScanOptions {
/**
* If true every node of the result will contain stat property, provided by fs.lstat or fs.stat
*/
stat?: boolean;
/**
* If true, on windows, normalize each path replacing each backslash \\\\ with a slash /
*/
normalize?: boolean;
/**
* If true, all symbolic links found will be included in the result. Could not work on Windows
*/
symbolicLinks?: boolean;
/**
* If true, all symbolic links will be followed, including even their content if they link to a folder.
* Could not work on Windows
*/
followLinks?: boolean;
/**
* If true, every node in the result will contain sizeInBytes property as the number of bytes of the content.
* If a node is a folder, only its considered inner files will be computed to have this size
*/
sizeInBytes?: boolean;
/**
* If true, every node in the result will contain size property. Same as sizeInBytes, but it
* is a string rounded to the second decimal digit and with an appropriate unit
*/
size?: boolean;
/**
* If true, every node in the result will contain hash property, computed by taking in consideration
* the name and the content of the node. If the node is a folder, all his considered inner files will be used by the algorithm
*/
hash?: boolean;
/**
* Hash algorithm used by cryptojs to return the hash
*/
hashAlgorithm?: 'md5' | 'sha1';
/**
* Hash encoding used by cryptojs to return the hash
*/
hashEncoding?: HexBase64Latin1Encoding;
/**
* If true, all hidden files and dirs will be included in the result. A hidden file or a directory
* has a name wich starts with a dot and in some systems like Linux are hidden
*/
showHidden?: boolean;
/**
* It is a number wich says the max depth the algorithm can reach scanning the given path.
* All files and dirs wich are beyound the max depth will not be considered by the algorithm
*/
depth?: number;
/**
* It is a regex or array of regex and all the matched paths will not be considered by the algorithm
*/
exclude?: RegExp | RegExp[];
/**
* It is an array of strings and all the files whose extension is not included in that array will be skipped by the algorithm.
* If value is undefined, all file extensions will be considered, if it is [], no files will be included
*/
extensions?: string[];
/**
* If true, folders whose user has not permissions will be skipped. An error will be thrown otherwise. Note: in fact every
* error thrown by fs calls will be ignored
*/
skipErrors?: boolean;
}
/**
* Interface of the options object used with "parse" or "parseTree" functions
*/
export interface ParseOptions {
/**
* If true, all symbolic links found will be included in the result. Could not work on Windows
*/
symbolicLinks?: boolean;
/**
* If true, all symbolic links will be followed, including even their content if they link to a folder.
* Could not work on Windows
*/
followLinks?: boolean;
/**
* If true, all hidden files and dirs will be included in the result. A hidden file or a directory
* has a name wich starts with a dot and in some systems like Linux are hidden
*/
showHidden?: boolean;
/**
* It is a number wich says the max depth the algorithm can reach scanning the given path.
* All files and dirs wich are beyound the max depth will not be considered by the algorithm
*/
depth?: number;
/**
* It is a regex or array of regex and all the matched paths will not be considered by the algorithm
*/
exclude?: RegExp | RegExp[];
/**
* It is an array of strings and all the files whose extension is not included in that array will be skipped by the algorithm.
* If value is undefined, all file extensions will be considered, if it is [], no files will be included
*/
extensions?: string[];
/**
* If true, folders whose user has not permissions will be skipped. An error will be thrown otherwise. Note: in fact every
* error thrown by fs calls will be ignored
*/
skipErrors?: boolean;
}
export declare type Callback = (dirTree: Dree, stat: Stats) => void;

@@ -72,3 +203,17 @@ /**

*/
export declare function scan(path: string, options?: Options, onFile?: Callback, onDir?: Callback): Dree;
export declare function scan(path: string, options?: ScanOptions, onFile?: Callback, onDir?: Callback): Dree;
/**
* Retrurns a string representation of a Directory Tree given a path to a directory or file
* @param {string} dirTree The path wich you want to inspect
* @param {object} options An object used as options of the function
* @return {string} A string representing the Directory Tree of the given path
*/
export declare function parse(path: string, options?: ParseOptions): string;
/**
* Retrurns a string representation of a Directory Tree given an object returned from scan
* @param {object} dirTree The object returned from scan, wich will be parsed
* @param {object} options An object used as options of the function
* @return {string} A string representing the object given as first parameter
*/
export declare function parseTree(dirTree: Dree, options?: ParseOptions): string;
export {};
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const path_1 = require("path");
const crypto_1 = require("crypto");
const fs_1 = require("fs");
var path_1 = require("path");
var crypto_1 = require("crypto");
var fs_1 = require("fs");
/* DREE TYPES */
/**
* Enum whose values are DIRECTORY or FILE
*/
var Type;

@@ -13,3 +16,3 @@ (function (Type) {

/* DEFAULT OPTIONS */
const DEFAULT_OPTIONS = {
var SCAN_DEFAULT_OPTIONS = {
stat: false,

@@ -27,10 +30,20 @@ normalize: false,

exclude: undefined,
extensions: undefined
extensions: undefined,
skipErrors: true
};
var PARSE_DEFAULT_OPTIONS = {
symbolicLinks: true,
followLinks: false,
showHidden: true,
depth: undefined,
exclude: undefined,
extensions: undefined,
skipErrors: true
};
/* SUPPORT FUNCTIONS */
function mergeOptions(options) {
let result = {};
function mergeScanOptions(options) {
var result = {};
if (options) {
for (const key in DEFAULT_OPTIONS) {
result[key] = (options[key] != undefined) ? options[key] : DEFAULT_OPTIONS[key];
for (var key in SCAN_DEFAULT_OPTIONS) {
result[key] = (options[key] !== undefined) ? options[key] : SCAN_DEFAULT_OPTIONS[key];
}

@@ -42,9 +55,24 @@ if (result.depth < 0) {

else {
result = DEFAULT_OPTIONS;
result = SCAN_DEFAULT_OPTIONS;
}
return result;
}
function mergeParseOptions(options) {
var result = {};
if (options) {
for (var key in PARSE_DEFAULT_OPTIONS) {
result[key] = (options[key] !== undefined) ? options[key] : PARSE_DEFAULT_OPTIONS[key];
}
if (result.depth < 0) {
result.depth = 0;
}
}
else {
result = PARSE_DEFAULT_OPTIONS;
}
return result;
}
function parseSize(size) {
const units = ['B', 'KB', 'MB', 'GB', 'TB'];
let i;
var units = ['B', 'KB', 'MB', 'GB', 'TB'];
var i;
for (i = 0; i < units.length && size > 1000; i++) {

@@ -56,17 +84,39 @@ size /= 1000;

function _scan(root, path, depth, options, onFile, onDir) {
if (options.depth && depth > options.depth) {
if (options.depth !== undefined && depth > options.depth) {
return null;
}
if (options.exclude && root != path) {
const excludes = (options.exclude instanceof RegExp) ? [options.exclude] : options.exclude;
if (excludes.some(pattern => pattern.test(path))) {
if (options.exclude && root !== path) {
var excludes = (options.exclude instanceof RegExp) ? [options.exclude] : options.exclude;
if (excludes.some(function (pattern) { return pattern.test(path); })) {
return null;
}
}
const relativePath = (root == path) ? '.' : path_1.relative(root, path);
const name = path_1.basename(path);
const stat = fs_1.statSync(path);
const lstat = fs_1.lstatSync(path);
const symbolicLink = lstat.isSymbolicLink();
const type = stat.isFile() ? Type.FILE : Type.DIRECTORY;
var relativePath = (root === path) ? '.' : path_1.relative(root, path);
var name = path_1.basename(path);
var stat;
try {
stat = fs_1.statSync(path);
}
catch (exception) {
if (options.skipErrors) {
return null;
}
else {
throw exception;
}
}
var lstat;
try {
lstat = fs_1.lstatSync(path);
}
catch (exception) {
if (options.skipErrors) {
return null;
}
else {
throw exception;
}
}
var symbolicLink = lstat.isSymbolicLink();
var type = stat.isFile() ? Type.FILE : Type.DIRECTORY;
if (!options.showHidden && name.charAt(0) === '.') {

@@ -78,9 +128,9 @@ return null;

}
let hash;
var hash;
if (options.hash) {
const hashAlgorithm = options.hashAlgorithm;
var hashAlgorithm = options.hashAlgorithm;
hash = crypto_1.createHash(hashAlgorithm);
hash.update(name);
}
const dirTree = {
var dirTree = {
name: name,

@@ -95,23 +145,38 @@ path: options.normalize ? path.replace(/\\/g, '/') : path,

case Type.DIRECTORY:
const children = [];
fs_1.readdirSync(path).forEach(file => {
const child = _scan(root, path_1.resolve(path, file), depth + 1, options, onFile, onDir);
if (child != null) {
children.push(child);
var children_1 = [];
var files = void 0;
try {
files = fs_1.readdirSync(path);
}
catch (exception) {
if (options.skipErrors) {
return null;
}
else {
throw exception;
}
}
files.forEach(function (file) {
var child = _scan(root, path_1.resolve(path, file), depth + 1, options, onFile, onDir);
if (child !== null) {
children_1.push(child);
}
});
if (options.sizeInBytes || options.size) {
const size = children.reduce((previous, current) => previous + current.sizeInBytes, 0);
var size = children_1.reduce(function (previous, current) { return previous + current.sizeInBytes; }, 0);
dirTree.sizeInBytes = size;
dirTree.size = options.size ? parseSize(size) : undefined;
if (!options.sizeInBytes) {
children.forEach(child => child.sizeInBytes = undefined);
children_1.forEach(function (child) { return child.sizeInBytes = undefined; });
}
}
if (options.hash) {
const hashEncoding = options.hashEncoding;
children_1.forEach(function (child) {
hash.update(child.hash);
});
var hashEncoding = options.hashEncoding;
dirTree.hash = hash.digest(hashEncoding);
}
if (children.length) {
dirTree.children = children;
if (children_1.length) {
dirTree.children = children_1;
}

@@ -121,7 +186,7 @@ break;

dirTree.extension = path_1.extname(path).replace('.', '');
if (options.extensions && options.extensions.indexOf(dirTree.extension) == -1) {
if (options.extensions && options.extensions.indexOf(dirTree.extension) === -1) {
return null;
}
if (options.sizeInBytes || options.size) {
const size = (options.followLinks ? stat.size : lstat.size);
var size = (options.followLinks ? stat.size : lstat.size);
dirTree.sizeInBytes = size;

@@ -131,5 +196,16 @@ dirTree.size = options.size ? parseSize(size) : undefined;

if (options.hash) {
const data = fs_1.readFileSync(path);
var data = void 0;
try {
data = fs_1.readFileSync(path);
}
catch (exception) {
if (options.skipErrors) {
return null;
}
else {
throw exception;
}
}
hash.update(data);
const hashEncoding = options.hashEncoding;
var hashEncoding = options.hashEncoding;
dirTree.hash = hash.digest(hashEncoding);

@@ -141,6 +217,6 @@ }

}
if (onFile && type == Type.FILE) {
if (onFile && type === Type.FILE) {
onFile(dirTree, options.followLinks ? stat : lstat);
}
else if (onDir && type == Type.DIRECTORY) {
else if (onDir && type === Type.DIRECTORY) {
onDir(dirTree, options.followLinks ? stat : lstat);

@@ -150,2 +226,97 @@ }

}
function skip(child, options, depth) {
return (!options.symbolicLinks && child.isSymbolicLink)
|| (!options.showHidden && child.name.charAt(0) === '.')
|| (options.extensions !== undefined && child.type === Type.FILE
&& (options.extensions.indexOf(child.extension) === -1))
|| (options.exclude instanceof RegExp && options.exclude.test(child.path))
|| (Array.isArray(options.exclude) && options.exclude.some(function (pattern) { return pattern.test(child.path); }))
|| (options.depth !== undefined && depth > options.depth);
}
function _parse(children, prefix, options, depth) {
var result = '';
var lines = children.map(function (child, index) {
var result = '';
if (options.depth !== undefined && depth > options.depth) {
return '';
}
if (options.exclude) {
var excludes = (options.exclude instanceof RegExp) ? [options.exclude] : options.exclude;
if (excludes.some(function (pattern) { return pattern.test(child); })) {
return '';
}
}
var name = path_1.basename(child);
var stat;
try {
stat = fs_1.statSync(child);
}
catch (exception) {
if (options.skipErrors) {
return null;
}
else {
throw exception;
}
}
var lstat;
try {
lstat = fs_1.lstatSync(child);
}
catch (exception) {
if (options.skipErrors) {
return null;
}
else {
throw exception;
}
}
var symbolicLink = lstat.isSymbolicLink();
var type = stat.isFile() ? Type.FILE : Type.DIRECTORY;
if (!options.showHidden && name.charAt(0) === '.') {
return '';
}
if (!options.symbolicLinks && symbolicLink) {
return '';
}
var extension = path_1.extname(child).replace('.', '');
if (options.extensions && type === Type.FILE && options.extensions.indexOf(extension) === -1) {
return '';
}
var last = symbolicLink ? '>>' : (type === Type.DIRECTORY ? '─> ' : '── ');
var newPrefix = prefix + (index === children.length - 1 ? ' ' : '│ ');
result += last + name;
if ((options.followLinks || !symbolicLink) && type === Type.DIRECTORY) {
var children_2;
try {
children_2 = fs_1.readdirSync(child).map(function (file) { return path_1.resolve(child, file); });
}
catch (exception) {
if (options.skipErrors) {
return null;
}
else {
throw exception;
}
}
result += children_2.length ? _parse(children_2, newPrefix, options, depth + 1) : '';
}
return result;
});
lines.filter(function (line) { return !!line; }).forEach(function (line, index, lines) {
result += prefix + (index === lines.length - 1 ? '└' + line : '├' + line);
});
return result;
}
function _parseTree(children, prefix, options, depth) {
var result = '';
children.filter(function (child) { return !skip(child, options, depth); }).forEach(function (child, index, children) {
var last = child.isSymbolicLink ? '>>' : (child.type === Type.DIRECTORY ? '─> ' : '── ');
var line = (index === children.length - 1) ? '└' + last : '├' + last;
var newPrefix = prefix + (index === children.length - 1 ? ' ' : '│ ');
result += prefix + line + child.name;
result += (child.children && (options.followLinks || !child.isSymbolicLink) ? _parseTree(child.children, newPrefix, options, depth + 1) : '');
});
return result;
}
/* EXPORTED FUNCTIONS */

@@ -161,5 +332,5 @@ /**

function scan(path, options, onFile, onDir) {
const root = path_1.resolve(path);
const opt = mergeOptions(options);
const result = _scan(root, root, 0, opt, onFile, onDir);
var root = path_1.resolve(path);
var opt = mergeScanOptions(options);
var result = _scan(root, root, 0, opt, onFile, onDir);
result.sizeInBytes = opt.sizeInBytes ? result.sizeInBytes : undefined;

@@ -169,1 +340,70 @@ return result;

exports.scan = scan;
/**
* Retrurns a string representation of a Directory Tree given a path to a directory or file
* @param {string} dirTree The path wich you want to inspect
* @param {object} options An object used as options of the function
* @return {string} A string representing the Directory Tree of the given path
*/
function parse(path, options) {
var result = '';
var root = path_1.resolve(path);
var opt = mergeParseOptions(options);
var name = path_1.basename(root);
result += name;
var stat;
try {
stat = fs_1.statSync(path);
}
catch (exception) {
if (options.skipErrors) {
return null;
}
else {
throw exception;
}
}
var lstat;
try {
lstat = fs_1.lstatSync(path);
}
catch (exception) {
if (options.skipErrors) {
return null;
}
else {
throw exception;
}
}
var symbolicLink = lstat.isSymbolicLink();
if ((opt.followLinks || !symbolicLink) && stat.isDirectory()) {
var children = void 0;
try {
children = fs_1.readdirSync(root).map(function (file) { return path_1.resolve(root, file); });
}
catch (exception) {
if (options.skipErrors) {
return null;
}
else {
throw exception;
}
}
result += children.length ? _parse(children, '\n ', opt, 1) : '';
}
return result;
}
exports.parse = parse;
/**
* Retrurns a string representation of a Directory Tree given an object returned from scan
* @param {object} dirTree The object returned from scan, wich will be parsed
* @param {object} options An object used as options of the function
* @return {string} A string representing the object given as first parameter
*/
function parseTree(dirTree, options) {
var result = '';
var opt = mergeParseOptions(options);
result += dirTree ? dirTree.name : '';
result += (dirTree.children ? _parseTree(dirTree.children, '\n ', opt, 1) : '');
return result;
}
exports.parseTree = parseTree;

17

package.json
{
"name": "dree",
"version": "1.2.2",
"version": "2.0.0",
"description": "A nodejs module wich helps you handle a directory tree providing you its abstraction through tested functions and a custom configuration.",

@@ -8,4 +8,6 @@ "main": "lib/index.js",

"scripts": {
"test": "node test/test",
"transpile": "tsc --p source"
"test": "mocha --reporter spec",
"cover": "istanbul cover node_modules/mocha/bin/_mocha test/test.js - - -R spec",
"full-test": "mocha --reporter spec test/test.js --scan",
"transpile": "tsc"
},

@@ -34,4 +36,11 @@ "repository": {

"devDependencies": {
"@types/node": "^10.12.23"
"@types/node": "^10.12.23",
"coveralls": "^3.0.2",
"istanbul": "^0.4.5",
"typescript": "^3.3.3"
},
"dependencies": {
"chai": "^4.2.0",
"mocha": "^5.2.0"
}
}

@@ -0,3 +1,5 @@

[![Build Status](https://travis-ci.org/euberdeveloper/dree.svg?branch=master)](https://travis-ci.org/euberdeveloper/dree)
# dree
A nodejs module wich helps you handle a directory tree. It provides you an object of a directory tree with custom configuration and optional callback method when a file or dir is scanned. With Typescript support.
A nodejs module wich helps you handle a directory tree. It provides you an object of a directory tree with custom configuration and optional callback method when a file or dir is scanned. You will also be able to turn the tree into a string representation. With Typescript support.

@@ -12,2 +14,4 @@ ## Install

### Get an object
Simple:

@@ -58,2 +62,42 @@

### Get a string
Simple:
```js
const dree = require('dree');
const string = dree.parse('./folder');
```
With custom configuration:
```js
const dree = require('dree');
const options = {
followLinks: true,
depth: 5,
exclude: /nofetchdir/g,
extensions: [ 'txt', 'jpg' ]
};
const string = dree.parse('./folder', options);
```
Get a string from an object:
```js
const dree = require('dree');
const tree = dree.scan('./folder');
const options = {
followLinks: true,
depth: 5,
exclude: /nofetchdir/g,
extensions: [ 'txt', 'jpg' ]
};
const string = dree.parseTree(tree, options);
```
## Result

@@ -67,8 +111,5 @@

│ └── firebase.json
│ └── notes.txt
│ └── server
│ └── server.ts
└── frontend
│ └── angular
│ ├── app.ts
│ └── index.html
└── .gitignore

@@ -89,3 +130,3 @@ ```

The result will be:
The object returned from scan will be:

@@ -142,2 +183,12 @@ ```json

```
With similar configurations, parse will return:
```
sample
└─> backend
├── firebase.json
├── hello.txt
└─> server
└── server.ts
```
## API

@@ -158,3 +209,3 @@

* `path`: Is of type `string`, and is the relative or absolute path the file or directory that you want to scan
* `options`: Optional. Is of type `object` and allows you to have customize the function behaviour.
* `options`: Optional. Is of type `object` and allows you to customize the function behaviour.
* `fileCallback`: Optional. Called each time a file is added to the tree. It provides you the node, wich **reflects** the fiven options, and its status returned by fs.stat (fs.lstat if `followLinks` option is enabled).

@@ -178,2 +229,3 @@ * `dirCallback`: Optional. Called each time a directory is added to the tree. It provides you the node, wich **reflects** the fiven options, and its status returned by fs.lstat (fs.stat if `followLinks` option is enabled).

* `extensions`: Default value: `undefined`. It is an array of strings and all the files whose extension is not included in that array will be skipped by the algorithm. If value is `undefined`, all file extensions will be considered, if it is `[]`, no files will be included.
* `skipErrors`: Default value: `true`. If true, folders whose user has not permissions will be skipped. An error will be thrown otherwise. Note: in fact every error thrown by `fs` calls will be ignored. Considere

@@ -196,2 +248,53 @@ **Result object parameters:**

### parse
**Syntax:**
`dree.parse(path, options)`
**Description:**
Given a path, returns a string representing its directory tree. The result could be customized with options. Executed syncronously. See __Usage__ to have an example.
**Parameters:**
* `path`: Is of type `string`, and is the relative or absolute path the file or directory that you want to parse
* `options`: Optional. Is of type `object` and allows you to customize the function behaviour.
**Options parameters:**
* `symbolicLinks`: Default value: `true`. If true, all symbolic links found will be included in the result. Could not work on Windows.
* `followLinks`: Default value: `false`. If true, all symbolic links will be followed, including even their content if they link to a folder. Could not work on Windows.
* `showHidden`: Default value: `true`. If true, all hidden files and dirs will be included in the result. A hidden file or a directory has a name wich starts with a dot and in some systems like Linux are hidden.
* `depth`: Default value: `undefined`. It is a number wich says the max depth the algorithm can reach scanning the given path. All files and dirs wich are beyound the max depth will not be considered by the algorithm.
* `exclude`: Default value: `undefined`. It is a regex or array of regex and all the matched paths will not be considered by the algorithm.
* `extensions`: Default value: `undefined`. It is an array of strings and all the files whose extension is not included in that array will be skipped by the algorithm. If value is `undefined`, all file extensions will be considered, if it is `[]`, no files will be included.
**Result string:**
The result will be a string representing the Directory Tree of the path given as first parameter. Folders will be preceded by `>` and symbolic links by `>>`.
### parseTree
**Syntax:**
`dree.parseTree(dirTree, options)`
**Description:**
The same as `parse`, but the first parameter is an object returned by `scan` function.
**Parameters:**
* `dirTree`: Is of type `object`, and is the object representing a Directory Tree that you want to parse into a string.
* `options`: Optional. Is of type `object` and allows you to customize the function behaviour.
**Options parameters:**
Same parameters of `parse`, with one more parameter, `skipErrors`: is the same parameter in `scan` options.
**Result string:**
The result will be a string representing the Directory Tree of the object given as first parameter. Folders will be preceded by `>` and symbolic links by `>>`.
## Note

@@ -215,1 +318,3 @@

Make sure you have the dev dependencies installed.
Note: There is also the script `npm run test-full`, wich contains also the tests for the scan function, but it is not a default choice, because results as absolute paths, file sizes and hash can be different with different systems and users.
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc