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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@bwt-st/utils

v0.2.1

Published

Tree-shakable, framework-agnostic utility functions for BWT-ST projects.

Readme

@bwt-st/utils

面向 BWT-ST 项目的无框架工具函数库,使用 ESM 命名导出并声明 sideEffects: false。适合表单校验、URL 处理、日期处理、浏览器能力判断和常用数据转换。

安装

pnpm add @bwt-st/utils

导入方式

推荐从根入口集中导入,现代打包器会根据实际使用情况进行 Tree Shaking:

import {
  clamp,
  formatDate,
  isEmail,
  isMobileDevice,
  withQuery,
} from '@bwt-st/utils'

也可以按类目使用子路径:

import { formatDate } from '@bwt-st/utils/date'
import { isMobileDevice } from '@bwt-st/utils/browser'

根入口和类目子路径都只导出命名 API,不提供默认导出。业务项目应避免动态拼接导入路径,以便构建工具分析依赖并移除未使用代码。

API 类目

array:数组处理

chunk 按大小切分数组;unique 按 Set 规则去重;uniqueBy 按计算键去重;groupBy 按计算键分组。

chunk([1, 2, 3, 4, 5], 2) // [[1, 2], [3, 4], [5]]
uniqueBy(users, (user) => user.id)

async:异步控制

sleep 延迟指定时间;withTimeout 为 Promise 增加超时限制。超时只会拒绝返回的 Promise,不会取消底层异步任务。

await sleep(300)
await withTimeout(loadUser(), 5_000)

browser:浏览器能力

公开函数:isBrowser、getDeviceType、isMobileDevice、isTabletDevice、isDesktopDevice、isTouchDevice、isIOS、isAndroid、canUseClipboard、copyText、readClipboardText、getViewportSize、isOnline、downloadBlob。

if (isMobileDevice()) {
  enableCompactLayout()
}

await copyText('复制内容')

设备识别只适合控制交互体验,不应作为权限或安全判断依据。浏览器能力函数在 SSR 或能力不可用时返回 false、null 或失败结果,不会假设浏览器对象始终存在。

data:数据校验

公开函数:isEmptyString、isBlank、isNonEmptyString、isEmptyArray、isNonEmptyArray、isEmptyObject、isNonEmptyObject、isEmptyValue、hasKeys、hasValues、isArrayOf、isRecordOf、isValidDate、isInteger、isPositiveNumber、isNonNegativeNumber、isInRange、isSafeInteger、isJsonString。

isEmptyValue(null) // true
isEmptyValue(0) // false
isInRange(80, 0, 100) // true

isEmptyValue 只将 null、undefined、空白字符串、空数组和空普通对象视为空;0、false 和 NaN 会被视为有值。

date:日期处理

公开函数:isDate、isValidDate、startOfDay、endOfDay、addDays、differenceInDays、isSameDay、formatDate。

formatDate(new Date('2026-01-02T09:05:06'), 'YYYY-MM-DD HH:mm:ss')
// '2026-01-02 09:05:06'

addDays('2026-01-01', 7)

日期函数支持 Date、日期字符串和毫秒时间戳,并按本地自然日处理。格式化令牌支持 YYYY、MM、DD、HH、mm、ss 和 SSS。日期输入无效时会抛出 TypeError。

function:函数控制

公开函数:noop、identity、once、debounce。

const search = debounce((keyword: string) => requestSearch(keyword), 300)
search('web')
search.cancel()

once 只执行原函数一次并缓存返回值;debounce 返回的函数带有 cancel() 方法,等待时间必须是非负有限数值。

number:数值处理

公开函数:clamp、roundTo。

clamp(120, 0, 100) // 100
roundTo(12.345, 2) // 12.35

clamp 要求 min <= max;roundTo 的小数位数必须是非负整数。

object:对象处理

公开函数:pick、omit。

const user = { id: 1, name: 'Ada', token: 'secret' }
pick(user, ['id', 'name'])
omit(user, ['token'])

两个函数都只处理自有属性、返回新对象且不会修改输入对象。

string:字符串处理

公开函数:capitalize、camelCase、truncate。

capitalize('hello') // 'Hello'
camelCase('user_name') // 'userName'
truncate('前端基础能力库', 6) // '前端基...'

truncate 的 length 表示最终字符串最大长度,后缀也计入长度。

type:类型判断

公开函数:isDefined、isNil、isString、isNumber、isFiniteNumber、isArray、isRecord、isPlainObject、hasOwn。

const value: unknown = getValue()

if (isRecord(value) && hasOwn(value, 'name') && isString(value.name)) {
  console.log(value.name)
}

这些函数同时提供 TypeScript 类型收窄。注意 isNumber 会将 NaN 和正负无穷判断为 number;需要有限数值时使用 isFiniteNumber。

url:URL 处理

公开函数:joinUrl、stringifyQuery、withQuery、getQueryParam、setQuery、removeQuery、parseQuery、parseUrl、resolveUrl、getUrlOrigin、isSameOrigin。

withQuery('/users?page=1', {
  status: 'active',
  tag: ['a', 'b'],
})
// '/users?page=1&status=active&tag=a&tag=b'

isSameOrigin('https://example.com/a', 'https://example.com/b') // true

查询参数中的 null 和 undefined 会被忽略,数组会生成多个同名参数。解析相对 URL 时需要提供绝对 baseUrl;无效 URL 通常返回 null,resolveUrl 解析失败时会抛出 TypeError。

regex:正则格式校验

公开函数:isMobilePhone、isEmail、isHttpUrl、isUrl、isIdCard、isLandlinePhone、isIntegerString、isDecimalString、isNumericString、isRmbAmount、isRmbCurrency、isUsdAmount、isUsdCurrency、isChinesePostalCode、isIPv4、isHexColor、isUsername。

isMobilePhone('13800138000') // true
isEmail('[email protected]') // true
isRmbCurrency('¥1,234.56') // true

所有校验函数只判断格式,不证明手机号、邮箱、身份证或地址真实有效。规则面向中国大陆常见企业项目;金额默认只接受非负数且最多两位小数。

兼容性

  • Node.js >=20.19.0
  • 支持 ESM 和现代 Tree Shaking 的构建工具
  • browser 类目在 SSR 中可以安全导入,但浏览器能力不可用时会返回保守结果
  • 详细的参数、返回值和逐函数示例可参阅仓库的 docs/utils/ 类目文档