统计一个目录里有多少 Markdown 文件,可以写个脚本。但如果希望在别的项目里也能用,不想每次复制脚本,就需要把它做成命令行工具。
Node 脚本能运行,和 npm 安装后能找到命令,是两件事。前者靠 node 执行文件,后者靠 package.json 的 bin 声明,把命令名指向入口。
写一个能直接运行的入口
新建目录 note-count,在里面创建 bin/note-count.cjs。使用 CommonJS,不需要配置 type。
#!/usr/bin/env node
const fs = require("fs");
const path = require("path");
const args = process.argv.slice(2);
if (args.includes("--help")) {
console.log("note-count [directory] -- count .md/.mdx files recursively");
process.exit(0);
}
if (args.length > 1) {
console.error("Only one directory is accepted");
process.exit(1);
}
function count(directory) {
return fs.readdirSync(directory, { withFileTypes: true }).reduce((sum, item) => {
if (
item.isSymbolicLink() ||
item.name === "node_modules" ||
item.name.startsWith(".")
)
return sum;
const full = path.join(directory, item.name);
return sum + (item.isDirectory() ? count(full) : /\.mdx?$/.test(item.name) ? 1 : 0);
}, 0);
}
try {
console.log(count(path.resolve(args[0] || ".")));
} catch (error) {
console.error(error.message);
process.exitCode = 1;
}
第一行是 shebang,在 Unix 系统上告诉命令行用 node 执行它;Windows 安装时 npm 会生成对应的命令包装。参数从 process.argv 的第三项开始取,前两项是运行时和入口路径。
目录默认是当前工作目录。隐藏文件、node_modules 和符号链接被跳过,避免把依赖目录算进去,也避免链接绕回来。这是这个小工具的统计规则,大小写不同的 .MD 目前不会计入。
路径不存在时,错误写到 stderr,退出码设为 1。调用脚本的 CI 可以据此判断失败,不需要从一行中文里猜结果。
让 npm 知道命令叫什么
同目录创建 package.json:
{
"name": "leyla-note-count-demo",
"version": "1.0.0",
"description": "Local-only CLI packaging experiment",
"bin": { "note-count": "bin/note-count.cjs" },
"files": ["bin"],
"license": "MIT"
}
bin 的键是命令名,值是包里的相对路径。files 控制打包范围,这里只包含 bin 目录;package.json 等 npm 必需文件仍会进入包。
node bin/note-count.cjs --help
node bin/note-count.cjs .
npm pack --dry-run
npm pack
最后一条生成 leyla-note-count-demo-1.0.0.tgz。在另一个空目录运行 npm init -y,然后安装生成的压缩包,路径替换成自己的实际位置:
npm install ../note-count/leyla-note-count-demo-1.0.0.tgz
npm exec -- note-count --help
npm exec -- note-count .
用一个包含两份 .md、一份 .mdx 和一份 .txt 的目录试一下,应输出 3。再试不存在的目录,确认不是输出 0 后正常退出。安装后的 —help 也能运行,才说明打包和命令入口接上了。
本地安装已经能检查完整链路,不需要为了测试发布到 npm。工具大一点以后,还可以补参数解析、忽略规则和异步遍历;现在同步遍历适合小目录,不适合拿来扫描很大的磁盘。bin 的规则可以查 npm package.json 文档。