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

get-file-tree

v1.0.3

Published

输出指定目录的目录树

Downloads

3

Readme

nodeScriptingTool

介绍

node.js编写的一些脚本工具

getFileTree.js

说在前面

我们在很多地方都可以看到有这样的目录树结构,目录树可以很好的介绍项目中各文件目录的用途,帮助读者了解整个项目结构。 image.png 由于自己在项目中需要用到这个目录树来进行项目结构介绍,但是在网上简单的找了一下,没找到自己想要的工具,于是就自己动手用node撸了一个,输出效果如上图↑↑↑。

代码实现

依赖模块

需要使用fs和path模块。

const fs = require("fs");
const path = require("path");

参数配置

执行node命令的时候可以携带参数,具体参数如下: 执行node getFileTree.js -h 或 node getFileTree.js -help 控制台会打印提示信息。 node getFileTree.js [参数1] [参数2] [参数3] [参数4] [参数5] 具体代码如下:

let basepath = "../"; //解析目录路径
let filterFile = ["node_modules", "\\..*"]; //过滤文件名,使用,隔开
let stopFloor = 10; //遍历层数
let generatePath = "./fileTree.txt"; //生成文件路径
let isFullPath = true; //是否输出完整路径

//获取入参
let args = process.argv.slice(2);
if (args[0] && (args[0] === "-h" || args[0] === "-help")) {
  console.log("node getFileTree.js [参数1] [参数2] [参数3] [参数4] [参数5]");
  console.log("参数说明");
  console.log("参数1:解析目录路径,默认为'../'");
  console.log(
    "参数2:过滤文件名,使用','隔开,支持正则表达式,默认为'node_modules', '\\..*'"
  );
  console.log("参数3:遍历文件最大层数,默认为10");
  console.log("参数4:生成文件路径,默认为'./fileTree.txt'");
  console.log("参数5:是否输出完整路径,默认为true");
  console.log("参数按顺序读取,不能省略,使用默认值需要输入' '占位,如下:");
  console.log("node getFileTree.js [参数1] ' ' [参数3] [参数4] [参数5]");
  process.exit();
}

if (args[0] && args[0] !== " ") {
  basepath = args[0]; //解析目录路径
}
if (args[1] && args[1] !== " ") {
  filterFile = args[1].split(","); //过滤文件名,使用,隔开
}
if (args[2] && args[2] !== " ") {
  stopFloor = args[2]; //遍历层数
}
if (args[3] && args[3] !== " ") {
  generatePath = args[3]; //生成文件路径
}
if (args[4] && args[4] === "f") {
  isFullPath = false; //是否输出完整路径
}

目录输出以目标文件夹为起始路径

比如我们需要生产目录树的文件夹路径为'../test',我们并不希望输出目录树每一个目录都会带上'../test'这一部分路径,所以应该将这一部分的路径删除。

function getPartPath(dirPath) {
  let base = basepath.split(/\/|\\/g);
  dirPath = dirPath.split(/\/|\\/g);
  while (base.length && dirPath.length && base[0] === dirPath[0]) {
    base.shift();
    dirPath.shift();
  }
  return dirPath.join("/");
}

过滤不想输出的目录文件

我们在打印目录树的时候也希望有些目录文件不被打印出来,如node_modules目录点开头的文件,程序默认的过滤规则为:let filterFile = ["node_modules", "\\..*"];

function isFilterPath(item) {
  for (let i = 0; i < filterFile.length; i++) {
    let reg = filterFile[i];
    if (item.match(reg) && item.match(reg)[0] === item) return true;
  }
  return false;
}

获取文件目录树

使用fs模块中的readdirSync获取目录下的文件目录列表; 使用fs模块中的statSync获取文件信息,isFile方法可以判断是文件还是目录。 是文件则将文件放进列表,是目录则需递归处理目录,最后输出目录树的json数据,具体代码如下:

function processDir(dirPath, dirTree = [], floor = 1) {
  if (floor > stopFloor) return;
  let list = fs.readdirSync(dirPath);
  list = list.filter((item) => {
    return !isFilterPath(item);
  });
  list.forEach((itemPath) => {
    const fullPath = path.join(dirPath, itemPath);
    const fileStat = fs.statSync(fullPath);
    const isFile = fileStat.isFile();
    const dir = {
      name: isFullPath ? getPartPath(fullPath) : itemPath,
    };
    if (!isFile) {
      dir.children = processDir(fullPath, [], floor + 1);
    }
    dirTree.push(dir);
  });
  return dirTree;
}

打印目录树

拼接目录树字符串。

function consoleTree(tree, floor = 1, str = "", adder = "───", isLast = false) {
  str += adder;
  for (let i = 0; i < tree.length; i++) {
    if (floor === 1 && i === 0) {
      fileTree += "\n" + "┌" + str + tree[i].name;
    } else if (
      (isLast || floor === 1) &&
      i === tree.length - 1 &&
      !tree[i].children
    ) {
      fileTree += "\n" + "└" + str + tree[i].name;
    } else {
      fileTree += "\n" + "├" + str + tree[i].name;
    }
    if (tree[i].children)
      consoleTree(
        tree[i].children,
        floor + 1,
        str,
        adder,
        (isLast || floor === 1) && i === tree.length - 1
      );
  }
}

目录树输出到文件中

先清空再写入。

function writeTree(filePath, content) {
  clearTxt(generatePath);
  fs.writeFileSync(filePath, `${content}`);
  console.log(content);
}

清空文件数据

function clearTxt(filePath) {
  fileTree = "";
  fs.writeFileSync(filePath, "");
}

完整代码

/*
 * @Author: zheng yong tao
 * @Date: 2022-03-16 21:27:07
 * @LastEditors: zheng yong tao
 * @LastEditTime: 2022-03-16 23:15:17
 * @Description:
 */

const fs = require("fs");
const path = require("path");

let basepath = "../"; //解析目录路径
let filterFile = ["node_modules", "\\..*"]; //过滤文件名,使用,隔开
let stopFloor = 10; //遍历层数
let generatePath = "./fileTree.txt"; //生成文件路径
let isFullPath = true; //是否输出完整路径

//获取入参
let args = process.argv.slice(2);
if (args[0] && (args[0] === "-h" || args[0] === "-help")) {
  console.log("node getFileTree.js [参数1] [参数2] [参数3] [参数4] [参数5]");
  console.log("参数说明");
  console.log("参数1:解析目录路径,默认为'../'");
  console.log(
    "参数2:过滤文件名,使用','隔开,支持正则表达式,默认为'node_modules', '\\..*'"
  );
  console.log("参数3:遍历文件最大层数,默认为10");
  console.log("参数4:生成文件路径,默认为'./fileTree.txt'");
  console.log("参数5:是否输出完整路径,默认为true");
  console.log("参数按顺序读取,不能省略,使用默认值需要输入' '占位,如下:");
  console.log("node getFileTree.js [参数1] ' ' [参数3] [参数4] [参数5]");
  process.exit();
}

if (args[0] && args[0] !== " ") {
  basepath = args[0]; //解析目录路径
}
if (args[1] && args[1] !== " ") {
  filterFile = args[1].split(","); //过滤文件名,使用,隔开
}
if (args[2] && args[2] !== " ") {
  stopFloor = args[2]; //遍历层数
}
if (args[3] && args[3] !== " ") {
  generatePath = args[3]; //生成文件路径
}
if (args[4] && args[4] === "f") {
  isFullPath = false; //是否输出完整路径
}


function getPartPath(dirPath) {
  let base = basepath.split(/\/|\\/g);
  dirPath = dirPath.split(/\/|\\/g);
  while (base.length && dirPath.length && base[0] === dirPath[0]) {
    base.shift();
    dirPath.shift();
  }
  return dirPath.join("/");
}

function isFilterPath(item) {
  for (let i = 0; i < filterFile.length; i++) {
    let reg = filterFile[i];
    if (item.match(reg) && item.match(reg)[0] === item) return true;
  }
  return false;
}

function processDir(dirPath, dirTree = [], floor = 1) {
  if (floor > stopFloor) return;
  let list = fs.readdirSync(dirPath);
  list = list.filter((item) => {
    return !isFilterPath(item);
  });
  list.forEach((itemPath) => {
    const fullPath = path.join(dirPath, itemPath);
    const fileStat = fs.statSync(fullPath);
    const isFile = fileStat.isFile();
    const dir = {
      name: isFullPath ? getPartPath(fullPath) : itemPath,
    };
    if (!isFile) {
      dir.children = processDir(fullPath, [], floor + 1);
    }
    dirTree.push(dir);
  });
  return dirTree;
}

console.log("获取中,请稍后……");
let dirTree = [];
dirTree = processDir(basepath, dirTree);
let fileTree = '';

function consoleTree(tree, floor = 1, str = "", adder = "───", isLast = false) {
  str += adder;
  for (let i = 0; i < tree.length; i++) {
    if (floor === 1 && i === 0) {
      fileTree += "\n" + "┌" + str + tree[i].name;
    } else if (
      (isLast || floor === 1) &&
      i === tree.length - 1 &&
      !tree[i].children
    ) {
      fileTree += "\n" + "└" + str + tree[i].name;
    } else {
      fileTree += "\n" + "├" + str + tree[i].name;
    }
    if (tree[i].children)
      consoleTree(
        tree[i].children,
        floor + 1,
        str,
        adder,
        (isLast || floor === 1) && i === tree.length - 1
      );
  }
}
console.log("生成中,请稍后……");
function writeTree(filePath, content) {
  clearTxt(generatePath);
  fs.writeFileSync(filePath, `${content}`);
  console.log(content);
}
function clearTxt(filePath) {
  fileTree = "";
  fs.writeFileSync(filePath, "");
}
consoleTree(dirTree);
writeTree(generatePath,fileTree);
console.log("生成结束");