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

tutils

v2.4.0

Published

200+ well-tested helper functions & classes for Node.js, including globbing, file watcher, zip, socket and so on | 200+ 个 NodeJS 工具库,顶 140+ 个 NPM 依赖,比如通配符、文件监听、网络库、Zip 压缩等

Downloads

1,032

Readme

TUtils

NPM version Downloads Build Status Coveralls Status

200+ 个 NodeJS 工具库,顶 140+ 个 NPM 依赖,比如通配符、文件监听、网络库、Zip 压缩等。

如果你有依赖强迫症,这一个库就能帮你省不少依赖,而且风格统一 + 全中文注释 + 稳定高性能。

特性

  1. 【强大】30+ 个独立模块,可单独引用;
  2. 【轻量】无外部依赖,所有源码含注释不超过 400K
  3. 【稳定】大量的单元测试(覆盖率 80%+)和生产实践,测试用例和社区同步;
  4. 【性能】鉴于功能专一,几乎所有模块在性能上稳超 NPM 社区模块;
  5. 【文档】完美全中文文档,VSCode/WebStorm/VS 等可智能提示。

为什么要重做轮子

  1. 追求纯净:不要为了一个简单功能,依赖几十个包;只支持 Node 最新稳定版(LTS),无历史包袱;
  2. 追求简洁:一个需求对应一种最短实现,而不是提供各种用法让用户按习惯选择;
  3. 追求性能:每个模块只专注自身功能,不做多余的操作,减少硬盘读写和内存消耗;
  4. 追求统一:统一的命名和设计,可以做到举一反三,过目不忘,而不用每次都要翻文档;
  5. 追求方便:一次安装,即可直接使用所有功能;
  6. 很多 NPM 包对中日韩文支持不好。

TUtils 总体上提供了“一站式”的使用方式,为你省去在 NPM 上查找、对比模块的烦恼。

安装

npm install tutils --save

注意:TUtils 基于 ES2018 编写,仅支持 Node v10.12 或更高版本。

一行代码引用所有模块:

const tutils = require("tutils")

或者,单独引入任一模块:

const fsSync = require("tutils/fileSystemSync")
const fs = require("tutils/fileSystem")
const mfs = require("tutils/memoryFileSystem")
const watcher = require("tutils/fileSystemWatcher")
const matcher = require("tutils/matcher")
const path = require("tutils/path")
const zipFile = require("tutils/zipFile")

const request = require("tutils/request")
const server = require("tutils/httpServer")
const ws = require("tutils/webSocket")
const net = require("tutils/net")
const url = require("tutils/url")

const ps = require("tutils/process")
const vm = require("tutils/vm")
const worker = require("tutils/workerPool")

const ansi = require("tutils/ansi")
const commandLine = require("tutils/commandLine")
const logger = require("tutils/logger")

const base64 = require("tutils/base64")
const crypto = require("tutils/crypto")
const html = require("tutils/html")
const js = require("tutils/js")
const json = require("tutils/json")
const css = require("tutils/css")

const lineColumn = require("tutils/lineColumn")
const sourceMap = require("tutils/sourceMap")
const textWriter = require("tutils/textWriter")
const textDocument = require("tutils/textDocument")

const asyncQueue = require("tutils/asyncQueue")
const deferred = require("tutils/deferred")
const eventEmitter = require("tutils/eventEmitter")

const require = require("tutils/require")
const resolver = require("tutils/resolver")
const jsx = require("tutils/jsx")
const tpl = require("tutils/tpl")
const misc = require("tutils/misc")

API 文档

点击查看生成的 API 文档

模块列表

目录

文件操作

fileSystemSync

提供创建、移动、复制、搜索文件和文件夹相关的工具函数,所有函数均可放心地直接调用。

const fs = require("tutils/fileSystemSync")

// 判断存在
fs.existsFile("dir/foo.txt") // 判断文件是否存在
fs.existsDir("dir") // 判断文件夹是否存在
fs.getStat("dir/foo") // 读取路径信息,比如是否是文件夹,大小、最后修改时间

// 读取文件
fs.readFile("dir/foo.jpg") // 读取二进制文件,返回 Buffer
fs.readText("dir/foo.txt") // 读取文本文件,返回字符串
fs.readText("dir/foo.txt", false) // 读取文本文件,如果文件不存在返回 null,而不是报错

// 写入文件
fs.writeFile("dir/foo.txt", "Hello world") // 覆盖已有文件,如果文件不存在则自动创建
fs.writeFile("dir/foo.txt", "Hello world", false) // 不覆盖已有文件
fs.appendFile("dir/foo.txt", "Hello world") // 追加到文件末尾

// 复制和移动文件
fs.copyFile("dir/foo.txt", "dir/copied.txt") // 比先读取再写入快
fs.moveFile("dir/foo.txt", "dir/moved.txt") // 比先复制再删除快

// 删除文件
fs.deleteFile("dir/foo.txt") // 如果文件不存在则忽略

// 遍历文件夹
fs.glob("*.txt") // 搜索当前文件夹下所有 .txt 文件
fs.glob(["*.{js,jsx}", "!node_modules"], "dir") // 搜索 dir 文件夹下所有 .js/.jsx 文件,并忽略 node_modules
fs.readDir("dir") // 读取文件夹下的文件列表(仅一级)
fs.walk("dir", { // 更底层地遍历
	file(path) {
		console.log("发现文件:", path)
	},
	dir(path) {
		console.log("发现文件夹:", path)
	}
})

// 创建文件夹
fs.createDir("dir") // 文件夹已存在则忽略
fs.createTempDir() // 在系统临时目录创建空文件夹
fs.ensureDirExists("dir/foo.txt") // 确保所在文件夹存在

// 复制和移动文件夹
fs.copyDir("dir", "copied") // 比先读取再写入快
fs.moveDir("dir", "moved") // 比先复制再删除快

// 删除文件夹
fs.deleteDir("dir") // 自动删除内部所有子文件和文件夹
fs.cleanDir("dir") // 清空文件夹,比先删除再创建快
fs.deleteParentDirIfEmpty("dir/foo.txt") // 删除空文件夹
为什么不使用 Node.js 自带的 fs 模块?

自带的 fs 模块更接近操作系统底层,在有些细节上并不合需求,比如创建文件时,无法自动创建所在文件夹;读取文本文件时不跳过 BOM 字符;遍历、复制文件夹时不支持递归;如果你对操作系统不熟,很可能踩坑。

fileSystem

类似 fileSystemSync,提供创建、移动、复制、搜索文件和文件夹相关的工具函数,但是异步的(更快),所有函数均需要使用 await 语法等待结果。

const { fs } = require("tutils/fileSystem")

// 用法同 fileSystemSync,唯一区别是需要加 await
await fs.writeFile("foo.txt", "Hello world")

| npm 包名 | TUtils 对应的函数/类 | | ------------------- | ----------------------------------------------- | | graceful-fs | FileSystem | | fs-extra | FileSystem | | graceful-fs-extra | FileSystem | | mkdirp | FileSystem.createDir | | make-dir | FileSystem.createDir | | cp-file | FileSystem.copFile | | cpy | FileSystem.copFile | | ncp | FileSystem.copyDir | | copy-files-tree | FileSystem.copyDir | | clean-dir | FileSystem.cleanDir | | delete | FileSystem.deleteDir | | del | FileSystem.deleteDir | | rimraf | FileSystem.deleteDir, FileSystem.deleteFile | | node-glob | FileSystem.glob | | fast-glob | FileSystem.glob | | globby | FileSystem.glob | | glob-all | FileSystem.glob | | walker | FileSystem.walk | | walkdir | FileSystem.walk | | move-file | FileSystem.moveFile | | path-exists | FileSystem.existsFile, FileSystem.existsDir |

memoryFileSystem

内存文件系统提供了和 FileSystem 完全相同的接口,但它会将数据保存到内存,避免多次硬盘读写。

使用 MemoryFileSystem 可以在不改变程序逻辑的情况下,实现类似 git --dry-runnpm publish --dry-run 的功能。

const { MemoryFileSystem } = require("tutils/memoryFileSystem")
const fs = new MemoryFileSystem()

// 之后用法同 fileSystem
await fs.writeFile("foo.txt", "Hello world")

| npm 包名 | TUtils 对应的函数/类 | | ----------- | -------------------- | | memory-fs | MemoryFileSystem | | mem-fs | MemoryFileSystem | | memfs | MemoryFileSystem |

fileSystemWatcher

监听文件的新增、修改和删除。

  • 支持 Windows/OSX/Linux
  • 可同时监听多个目标,且监听列表可动态增删
  • 支持非轮询的监听方式(性能高、占用内存小)
  • 支持忽略特定路径(以提高性能)
  • 支持暂停和恢复
  • 纯 JS 实现,不会安装失败
const { FileSystemWatcher } = require("tutils/fileSystemWatcher")

const watcher = new FileSystemWatcher({
	ignore: [".DS_Store", "Desktop.ini", "Thumbs.db", "ehthumbs.db", "*~", "*.tmp", ".git", ".vs", "node_modules"]
})
watcher.on("change", path => { console.log("修改:", path) })
watcher.on("delete", path => { console.log("删除:", path) })
watcher.on("create", path => { console.log("创建:", path) })
watcher.on("createDir", path => { console.log("创建文件夹:", path) })
watcher.on("deleteDir", path => { console.log("删除文件夹:", path) })
watcher.add(process.cwd(), () => { console.log("开始监听...") })

// 可以继续监听第二个文件夹,根文件夹必须已存在
watcher.add("dir", () => { console.log("添加监听...") })
为什么不使用 Node.js 自带的 fs.watch

自带的 fs 拥有诸多限制,比如可能误报、不稳定。 FileSystemWatcher 内部依然使用了自带的 fs.watch,但做了很多判断使得结果更符合作者预期。

| npm 包名 | TUtils 对应的函数/类 | | ----------- | -------------------- | | chokidar | FileSystemWatcher | | gaze | FileSystemWatcher | | sane | FileSystemWatcher | | watchpack | FileSystemWatcher |

matcher

判断路径是否符合规则,支持通配符、正则和自定义函数。

通配符语法同 .gitignore 文件,支持以下功能:

  • ?: 匹配固定一个字符,但 / 和文件名开头的 . 除外
  • *: 匹配任意个字符,但 / 和文件名开头的 . 除外
  • **: 匹配任意个字符,但文件名开头的 . 除外
  • [abc]: 匹配方括号中的任一个字符
  • [a-z]: 匹配 a 到 z 的任一个字符
  • [!abc]: 匹配方括号中的任一个字符以外的字符
  • {abc,xyz}: 匹配大括号中的任一种模式
  • \: 表示转义字符,如 \[ 表示 [ 按普通字符处理
  • !xyz:如果通配符以 ! 开头,表示排除匹配的项,注意如果排除了父文件夹,出于性能考虑,无法重新包含其中的子文件
const matcher = require("tutils/matcher")

// 判断是否匹配
matcher.match("/path.js", "/*.js") // true
matcher.match("/path.js", [/\.js/, "!node_modules"]) // true

| npm 包名 | TUtils 对应的函数/类 | | ------------- | -------------------- | | glob | Matcher | | node-glob | Matcher | | matcher | Matcher, match | | minimatch | match | | micromatch | match | | anymatch | match | | glob-base | Matcher.base | | glob-parent | Matcher.base | | is-glob | isGlob |

path

对文件路径的操作,扩充 Node.js 自带 path 模块的功能。

注意本模块只处理路径字符串,并不会真的访问硬盘。

const path = require("tutils/path")

// 路径格式化
path.resolvePath("foo/goo/hoo", "../relative") // 转绝对路径
path.relativePath("foo/goo/hoo", "../relative") // 转相对路径
path.joinPath("foo/goo/hoo", "../relative") // 合并路径
path.normalizePath("foo/goo/hoo/../relative") // 规范化路径
path.isAbsolutePath("foo/goo/hoo") // 是否是绝对路径

// 读写文件夹
path.getDir("/root/foo.txt") // "/root"
path.setDir("/root/foo.txt", "goo") // "goo/foo.txt"
path.getRoot("/root/goo/foo.txt") // "/root"
path.setRoot("/root/goo/foo.txt", "/user") // "/user/goo/foo.txt"

// 读写文件名
path.getName("/root/foo.txt") // "foo.txt"
path.setName("/root/foo.txt", "goo.jpg") // "/root/goo.jpg"
path.prependName("foo/goo.txt", "fix_") // "foo/fix_goo.txt"
path.appendName("foo/goo.src.txt", "_fix") // "foo/goo_fix.src.txt"
path.appendIndex("foo/goo.src.txt") // "foo/goo_2.src.txt"

// 读写扩展名
path.getExt("/root/foo.txt")
path.setExt("/root/foo.txt", ".jpg") // "/root/foo.jpg"

// 路径判断
path.pathEquals("/root", "/root") // 判断路径是否相同,在 Windows 忽略大小写
path.containsPath("/root", "/root/foo") // 判断路径父子包含关系
path.deepestPath("/root", "/root/foo") // 获取最深路径
path.commonDir("/root/foo", "/root/foo/goo") // 获取公共文件夹

| npm 包名 | TUtils 对应的函数/类 | | ------------------ | -------------------- | | rename-extension | setExt | | changefilesname | setName | | is-relative | isAbsolutePath | | is-absolute | isAbsolutePath | | normalize-path | normalizePath | | path-is-inside | containsPath | | contains-path | containsPath |

zipFile(v2.1.6 新增)

快速压缩、解压 Zip 文件。支持局部解压及更新部分文件。

const zipFile = require("tutils/zipFile")

// 快速压缩、解压
zipFile.compressFolder("dir") // 快速压缩 dir 文件夹中的内容为 dir.zip
zipFile.extractZip("dir.zip") // 快速将 dir.zip 解压到 dir 文件夹

// 更复杂操作
const file = zipFile.ZipFile.fromBuffer(buffer)
file.addFile("t.txt") // 添加文件
const result = file.compress() // 重新压缩

| npm 包名 | TUtils 对应的函数/类 | | ------------- | -------------------- | | unzip | extractZip | | adm-zip | ZipFile | | extract-zip | extractZip |

网络

request

在 Node.js 提供类似发送 Ajax 请求的功能。

const request = require("tutils/request")

// 最简单的请求
console.log((await request.request("https://www.baidu.com")).text)

// POST 一个 json 接口,并保存 Cookie
const cookieJar = new request.CookieJar()
const response = await request.request("/api/post", {
	method: "POST",
	dataType: "json",
	data: {
		foo: 1
	},
	headers: {
		"X-Request-With": "XMLHTTPRequest"
	},
	cookieJar: cookieJar
})
console.log(response.json)

| npm 包名 | TUtils 对应的函数/类 | | ----------------- | -------------------- | | request | request | | got | request | | axios | request | | wreck | request | | cookiejar | CookieJar | | touch-cookiejar | CookieJar |

httpServer

创建一个 HTTP 服务器,提供 Cookie、文件上传、Session 会话等扩展功能。

const httpServer = require("tutils/httpServer")

const server = new httpServer.HTTPServer({}, (req, res) => {
	res.end(req.href)
})
server.listen(8080)

| npm 包名 | TUtils 对应的函数/类 | | ----------------- | --------------------- | | express | HTTPServer | | koa | HTTPServer | | http-server | HTTPServer | | body-parser | HTTPRequest.body | | cookie-parser | HTTPRequest.cookies | | cookie-sessions | HTTPServer.sessions | | multipart | HTTPRequest.files |

webSocket

创建一个 WebSocket 服务器,同浏览器端原生 WebSocket 通信。

const webSocket = require("tutils/webSocket")

const server = new webSocket.WebSocketServer("ws://localhost:8080")
server.start()
server.on("connection", ws => {
	ws.send("hello")
})

const client = new webSocket.WebSocket("ws://localhost:8080")
client.on("message", data => {
	console.log(data)
	client.send("hello")
})

| npm 包名 | TUtils 对应的函数/类 | | ------------------ | -------------------- | | ws | WebSocket | | websocket-driver | WebSocket |

net

提供网络相关的工具函数。

const net = require("tutils/net")

console.log(net.remoteIP()) // 打印本机 IP

| npm 包名 | TUtils 对应的函数/类 | | ----------- | -------------------- | | public-ip | remoteIP |

url

对网络地址的操作,扩充 Node.js 自带 url 模块的功能。

const url = require("tutils/url")

// 地址格式化
url.resolveURL("http://example.com", "foo") // 转绝对地址
url.relativeURL("http://example.com", "http://example.com/foo") // 转相对地址
url.normalizeURL("http://example.com/foo/../relative") // 规范化地址
url.setBaseURL("foo", "base") // 设置基路径

// 地址判断
url.isAbsoluteURL("http://example.com/foo") // 是否是绝对地址
url.isExternalURL("http://example.com/foo") // 是否是其它站点的地址

// 查找并替换地址
url.replaceURL("请点击 http://example.com 继续", url => `<a href="${url}">${url}</a>`) // "请点击 <a href="http://example.com">http://example.com</a> 继续"

| npm 包名 | TUtils 对应的函数/类 | | ------------------ | -------------------- | | resolve-pathname | resolveURL | | relative-url | relativeURL | | normalize-url | normalizeURL | | is-relative-url | isAbsoluteURL | | get-urls | replaceURL | | linkify-it | replaceURL |

进程

process

启动子进程、设置当前进程退出回调。

const process = require("tutils/process")

// 执行命令
process.exec("echo hi")

// 打开浏览器
process.open("http://tealui.com")

// 设置进程退出后的回调,可通过 process.offExit 解绑
process.onExit(() => {
	console.log("退出了")
})

| npm 包名 | TUtils 对应的函数/类 | | ------------- | -------------------- | | cross-spawn | exec | | execa | exec | | open | open | | signal-exit | onExit, offExit |

vm

在沙盒中执行指定的 JavaScript 代码。类似 eval,但不能访问当前范围的变量。

注意本函数不提供安全隔离,不能用于执行不信任的代码

const vm = require("tutils/vm")
vm.runInVM(`var x = 1`)

workerPool

线程池,可以利用多核 CPU 同时执行多个复杂计算。

const { WorkerPool } = require("tutils/workerPool")

const pool = new WorkerPool(data => data[0] + data[1]) // 这个函数将在子线程执行,函数无法使用闭包
await pool.exec([1, 2]) // 3

| npm 包名 | TUtils 对应的函数/类 | | --------------------- | -------------------- | | worker-threads-pool | WorkerPool |

命令行

ansi

提供命令行输出内容的格式化功能。

const ansi = require("tutils/ansi")

// 颜色
console.log(ansi.color("红色", ansi.ANSIColor.red))
console.log(ansi.backgroundColor("红色", ansi.ANSIColor.red))
console.log(ansi.removeANSICodes("...")) // 删除颜色

// 格式化(支持中文)
console.log(ansi.truncateString("很长的内容", "...")) // 超出命令行宽度则截断
console.log(ansi.wrapString("很长的内容")) // 超出命令行宽度则换行
console.log(ansi.formatList(["a", "ab"])) // 显示一个列表
console.log(ansi.formatTree([{indent: 0, label: "x"}, {indent: 1, label: "x1"}])) // 显示一个树
console.log(ansi.formatTable([["a", "ab"], ["a2", "ab2"]])) // 显示一个表格
console.log(ansi.formatCodeFrame("var a = 1\nvar b = 2", 1, 8) // 显示一段代码,带行号
console.log(ansi.ansiToHTML("")) // 转 HTML,保留颜色和其它格式

| npm 包名 | TUtils 对应的函数/类 | | ---------------------- | ---------------------------------- | | ansi-color | color | | ansi-colors | color | | chalk | bold, color, backgroundColor | | kleur | bold, color, backgroundColor | | ansi-style-codes | ANSIColor | | ansi-regex | ansiCodeRegExp | | strip-ansi | removeANSICodes | | strip-color | removeANSICodes | | ansi-stripper | removeANSICodes | | cli-truncate | truncateString | | ansi-color-table | formatTable | | chunk-text | wrapString | | wrap-ansi | wrapString | | cli-columns | formatList | | console-log-tree | formatTree | | ansi-color-table | formatTable | | columnify | formatTable | | formatter-codeframe | formatCodeFrame | | ansicolor | ansiToHTML | | ansi-to-html | ansiToHTML | | ansi-html | ansiToHTML | | stream-ansi2html | ansiToHTML | | string-width | getStringWidth | | monospace-char-width | getCharWidth |

commandLine

提供命令行操作。

const commandLine = require("tutils/commandLine")

// 光标
commandLine.hideCursor() // 隐藏光标,使用 commandLine.showCursor() 还原

// 清空命令行
commandLine.clear()

// 解析命令行参数
commandLine.parseCommandLineArguments()

// 格式化帮助命令
commandLine.formatCommandLineOptions({
	"--x": {
		"alias": "-x",
		"description": "说明"
	}
})

// 读取命令行输入
const name = await commandLine.input("请输入名字:")
console.log(name)

const choice = await commandLine.select(["打开", "关闭"], "请选择一个:")
console.log(choice)

| npm 包名 | TUtils 对应的函数/类 | | ---------------------- | ------------------------------------------------------- | | show-terminal-cursor | showCursor | | hide-terminal-cursor | hideCursor | | cli-cursor | showCursor, hideCursor | | restore-cursor | showCursor | | meow | parseCommandLineArguments, formatCommandLineOptions | | yargs | parseCommandLineArguments, formatCommandLineOptions | | clear-cli | clear | | node-console-input | input |

logger

const { Logger } = require("tutils/logger")
const logger = new Logger()

// 打印
logger.fatal("Hello world")
logger.error("Hello world")
logger.warning("Hello world")
logger.info("Hello world")
logger.success("Hello world")
logger.log("Hello world")
logger.debug("Hello world")
logger.trace("Hello world")

// 进度条
logger.showProgress("载入中") // 使用 logger.hideProgress() 隐藏

const taskId = loggger.begin("读取文件")
// ...执行读取文件操作...
logger.end(taskId)

| npm 包名 | TUtils 对应的函数/类 | | ----------- | -------------------- | | logger | Logger | | fancy-log | Logger |

编码、解析

base64

快速实现 Base64 编码,中文会先编码。

const base64 = require("tutils/base64")

base64.encodeBase64("")
base64.decodeBase64("")

base64.encodeDataURI("") // 生成 base64 的 data: 地址
base64.decodeDataURI("data: image/png;base64, ...") // 读取 base64 的 data: 地址

| npm 包名 | TUtils 对应的函数/类 | | ------------ | -------------------------------- | | js-base64 | encodeBase64, decodeBase64 | | data-urlse | encodeDataURI, decodeDataURI |

crypto

快速实现加密算法。

const crypto = require("tutils/crypto")

crypto.md5("x") // 计算 MD5 值
crypto.sha1("x") // 计算 SHA-1 值

| npm 包名 | TUtils 对应的函数/类 | | -------- | -------------------- | | md5 | md5 | | sha1 | sha1 |

html

const html = require("tutils/html")

| npm 包名 | TUtils 对应的函数/类 | | ---------------------- | -------------------------- | | ent | encodeHTML, decodeHTML | | entities | encodeHTML, decodeHTML | | he | encodeHTML, decodeHTML | | html-entities | encodeHTML | | decode-html | decodeHTML | | html-decoder | decodeHTML | | html-entity-decoder | decodeHTML | | html-encoder-decoder | encodeHTML, decodeHTML | | html-parser | parseHTML |

js

const js = require("tutils/js")

| npm 包名 | TUtils 对应的函数/类 | | ------------------ | -------------------- | | js-string-escape | encodeJS |

json

const json = require("tutils/json")

// 读取 JSON
json.readJSON("path.json") // 支持注释和末尾多余的逗号
json.normalizeJSON("{a:1,}") // 删除 JSON 字符串中的注释和末尾多余的逗号

// 写入 JSON
json.writeJSON("path.json", {}) // 安全写入 JSON 数据

| npm 包名 | TUtils 对应的函数/类 | | --------------------- | -------------------- | | strip-json-comments | normalizeJSON | | load-json-file | readJSON | | write-json-file | writeJSON |

css

const css = require("tutils/css")

| npm 包名 | TUtils 对应的函数/类 | | -------- | -------------------- | | cssesc | encodeCSS |

生成代码

lineColumn

计算行列号

const lineColumn = require("tutils/lineColumn")

lineColumn.indexToLineColumn("", 0)

| npm 包名 | TUtils 对应的函数/类 | | ------------------- | ---------------------------------------- | | find-line-column | indexToLineColumn, lineColumnToIndex | | lines-and-columns | LineMap |

sourceMap

读写 Source Map。

const sourceMap = require("tutils/sourceMap")

// 修改源映射
const map = new sourceMap.SourceMapBuilder({ /* 已存在的 map*/ })
map.addMapping(1, 2)
const output = map.toJSON() // 生成的新 map

| npm 包名 | TUtils 对应的函数/类 | | -------------------- | --------------------------------- | | source-map | SourceMapBuilder | | convert-source-map | SourceMapBuilder | | merge-source-map | SourceMapBuilder.applySourceMap |

textWriter

同时生成代码及 Source Map。

const { TextWriter, SourceMapTextWriter } = require("tutils/textWriter")

const writer = new SourceMapTextWriter()
writer.write("hello")

console.log(writer.toString())
console.log(writer.sourceMap)

| npm 包名 | TUtils 对应的函数/类 | | ----------------------- | --------------------- | | string-builder | TextWriter | | source-list-map | SourceMapTextWriter | | fast-sourcemap-concat | SourceMapTextWriter |

textDocument

动态修改、拼接字符串并生成 Source Map。

const { TextDocument, replace, insert } = require("tutils/textDocument")

const data = replace({
	content: "var a = 1",
	path: "source.js"
}, /\bvar\b/g, "let")
console.log(data.content)
console.log(data.sourceMap)

| npm 包名 | TUtils 对应的函数/类 | | -------------- | -------------------- | | magic-string | TextDocument |

异步

asyncQueue

串联执行异步任务。

const { AsyncQueue } = require("tutils/asyncQueue")

const asyncQueue = new AsyncQueue()
await asyncQueue.then(async () => { /* 异步操作 1 */ })
await asyncQueue.then(async () => { /* 异步操作 2 */ })
await asyncQueue.then(async () => { /* 异步操作 3 */ })

| npm 包名 | TUtils 对应的函数/类 | | ----------------- | -------------------- | | asyncqueue | AsyncQueue | | node-asyncqueue | AsyncQueue |

deferred

类似 Promise,但可以更灵活地阻塞和回复。

const { Deferred } = require("tutils/deferred")

const deferred = new Deferred()
deferred.reject() // 开始执行异步操作
setTimeout(() => {
	deferred.resolve() // 异步操作结束
}, 2000)

await deferred

| npm 包名 | TUtils 对应的函数/类 | | ---------- | -------------------- | | deferred | Deferred |

eventEmitter

同原生的 events 模块,但支持异步事件。

const { EventEmitter } = require("tutils/eventEmitter")

const events = new EventEmitter()
events.on("error", data => console.log(data))  // 绑定 error 事件
await events.emit("error", "hello")            // 触发 error 事件,输出 hello

| npm 包名 | TUtils 对应的函数/类 | | ---------- | -------------------- | | events | EventEmitter | | tappable | EventEmitter |

其它

require

允许直接载入 ES 模块代码;允许载入全局安装的模块。

const { registerESMLoader, addGlobalPath } = require("tutils/require")

registerESMLoader()
require("./esm.js")

addGlobalPath("dir") // require 时会从 dir 搜索模块

| npm 包名 | TUtils 对应的函数/类 | | ---------------- | -------------------- | | esm | registerESMLoader | | require-global | addGlobalPath |

resolver 模块

类似 require.resolve,但可提供更多的配置选择。

const { Resolver } = require("tutils/resolver")

const resolver = new Resolver()
const result = await resolver.resolve("tutils", process.cwd())

| npm 包名 | TPack-Utils 对应的函数/类 | | ------------------ | ------------------------- | | enhanced-resolve | Resolver |

jsx

const {jsx, Fragment} = require("tutils/jsx")

/** @jsx jsx */
/** @jsxFrag Fragment */
var div = <button id="my" disabled>Hello World</button>
console.log(div)

tpl

const tpl = require("tutils/tpl")

tpl.compileTPL(`{$.data + 2}`)({data: 1}) // "3"

| npm 包名 | TUtils 对应的函数/类 | | -------- | -------------------- | | ejs | compileTPL |

misc

const misc = require("tutils/misc")

misc.stripBOM("...") // 删除字符串开头的 UTF-8 BOM 字符
misc.randomString() // 生成指定长度的随机字符串
misc.insertSorted() // 插入排序
misc.formatDate(new Date("2016/01/01 00:00:00")) // 格式化指定的日期对象
misc.formatRelativeDate(new Date("2016/01/01 00:00:00")) // 格式化时间为类似“几分钟前”的格式
misc.formatHRTime(process.hrtime()) // 格式化时间间隔
misc.formatSize(1024) // 格式化字节大小,1KB

| npm 包名 | TUtils 对应的函数/类 | | ---------------------- | -------------------- | | strip-bom | stripBOM | | sorted-array-type | insertSorted | | escape-string-regexp | escapeRegExp | | format-date | formatDate | | dateformat | formatDate | | Moment.js | formatDate | | node-dateformate | formatDate | | pretty-hrtime | formatHRTime | | pretty-time | formatHRTime | | pretty-bytes | formatSize | | pretty-size | formatSize |