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

@bigflower/utils

v1.1.0

Published

Common utility functions and constants

Readme

@bigflower/utils

通用工具函数与常量库。仅提供 ESM 产物,自带类型声明,支持 tree-shaking。

安装

pnpm add @bigflower/utils

使用

所有函数与常量均从包根部按需导入:

import { isEmail, thousand, DATE_FORMAT } from "@bigflower/utils";

isEmail("[email protected]"); // true
thousand(1234567.89, "¥", 2); // "¥1,234,567.89"
DATE_FORMAT; // "YYYY-MM-DD"

目录

  • 规则判断isNil isString isEmpty isNumeric isUrl isEmail isIpv4 isIpv6 isIp isBankNo isIdNo isMobile isSms isUsci isPassword
  • 格式化separator thousand decimal formatSize asterisk display
  • 解析parseIdNo
  • 对象merge
  • 文件getMimeType base64ToDataUrl bytesToBase64 base64ToBytes base64ToFile blobToFile downloadFile zipFiles unzipFiles
  • DOMopenWithForm loadScript
  • 常量

规则判断

所有判断函数都接受 unknown,传入非预期类型时返回 false,无需调用前额外做类型检查。

isNil

isNil(value: unknown): value is null | undefined;

判断值是否为 nullundefined,可用作类型守卫。

isNil(null); // true
isNil(undefined); // true
isNil(0); // false
isNil(""); // false

isString

isString(value: unknown): value is string;

判断值是否为原始字符串,可用作类型守卫。

isString("abc"); // true
isString(123); // false
isString(new String("abc")); // false,包装对象不算原始字符串

isEmpty

isEmpty(value: unknown): boolean;

判断值是否为空。判定规则依次为:null / undefined 为空;字符串和数组按 lengthMapSetsize;其余对象按自身可枚举键的数量;其他类型一律不为空。

isEmpty(null); // true
isEmpty(""); // true
isEmpty([]); // true
isEmpty(new Map()); // true
isEmpty({}); // true

isEmpty("  "); // false,空白字符不算空
isEmpty([1]); // false
isEmpty({ a: 1 }); // false
isEmpty(0); // false
isEmpty(false); // false

注意DateRegExp、函数等没有可枚举自有属性的对象会被判为空(isEmpty(new Date()) === true)。如需判断这类值,请自行加类型判断。

isNumeric

isNumeric(value: unknown): boolean;

判断值是否可转换为有限数值。数字类型要求为有限数;字符串会去除首尾空白后转换,空字符串不通过。

isNumeric(1.5); // true
isNumeric("12.5"); // true
isNumeric("  12  "); // true

isNumeric(NaN); // false
isNumeric(Infinity); // false
isNumeric(""); // false
isNumeric("abc"); // false
isNumeric(null); // false

注意:沿用 Number() 的解析规则,"0x10""1e3" 均返回 true

isUrl

isUrl(value: unknown, loose?: boolean): boolean; // loose 默认 false

判断值是否为合法 URL。默认仅接受 http:https:loosetrue 时接受任意协议。

isUrl("https://a.com/b?c=1"); // true
isUrl("ftp://a.com"); // false
isUrl("ftp://a.com", true); // true

isUrl("a.com"); // false,缺少协议
isUrl("/path"); // false,相对路径不是合法 URL

注意loosetruejavascript:alert(1) 也会通过。若结果会写入 href 等位置,请勿使用 loose

isEmail

isEmail(value: unknown): boolean;

判断值是否符合常见邮箱格式:@ 前后均非空且不含空白,域名部分至少含一个 .

isEmail("[email protected]"); // true
isEmail("user@example"); // false,域名缺少点号
isEmail("a [email protected]"); // false,含空白

注意:规则较宽松,[email protected] 也会通过;不校验国际化域名和实际可达性。

isIpv4

isIpv4(value: unknown): boolean;

判断值是否为 IPv4 地址。要求四段十进制数、每段不超过 255 且无前导零。

isIpv4("192.168.1.1"); // true
isIpv4("0.0.0.0"); // true

isIpv4("256.1.1.1"); // false,超出范围
isIpv4("192.168.01.1"); // false,含前导零
isIpv4("1.2.3"); // false,段数不足

isIpv6

isIpv6(value: unknown): boolean;

判断值是否为 IPv6 地址。支持 :: 零压缩写法,每组为 1~4 位十六进制。

isIpv6("2001:db8:0:0:0:0:2:1"); // true
isIpv6("2001:db8::2:1"); // true
isIpv6("::1"); // true

isIpv6("2001:db8"); // false,分组不足
isIpv6("::ffff:192.168.1.1"); // false,不支持 IPv4 映射格式

isIp

isIp(value: unknown): boolean;

判断值是否为 IPv4 或 IPv6 地址,等价于 isIpv4(value) || isIpv6(value)

isIp("192.168.1.1"); // true
isIp("::1"); // true
isIp("abc"); // false

isBankNo

isBankNo(value: unknown, loose?: boolean): boolean; // loose 默认 false

使用 Luhn 算法校验银行卡号。校验前会自动去除空格和连字符。默认接受 9~~20 位数字,loosetrue 时放宽到 8~~30 位。

isBankNo("4242424242424242"); // true
isBankNo("4242 4242 4242 4242"); // true,忽略空格
isBankNo("4242-4242-4242-4242"); // true,忽略连字符

isBankNo("4242424242424243"); // false,校验位不匹配
isBankNo("4242424242", true); // true,loose 放宽长度下限

isIdNo

isIdNo(value: unknown): boolean;

校验中国大陆 18 位居民身份证号码,同时验证出生日期的真实性和末位校验码。末位 x 不区分大小写。

isIdNo("11010519491231002X"); // true
isIdNo("11010519491231002x"); // true

isIdNo("110105194912310021"); // false,校验码错误
isIdNo("110105194913310021"); // false,出生月份非法
isIdNo("11010519491231"); // false,位数不足

注意:不支持 15 位一代身份证;出生日期按运行环境的本地时区解析。

isMobile

isMobile(value: unknown): boolean;

判断值是否为中国大陆手机号:以 13~19 开头的 11 位数字。

isMobile("13800138000"); // true
isMobile("12800138000"); // false,第二位非法
isMobile("1380013800"); // false,位数不足

isSms

isSms(value: unknown): boolean;

判断值是否为 6 位数字短信验证码。

isSms("123456"); // true
isSms("12345"); // false

isUsci

isUsci(value: unknown): boolean;

校验 18 位统一社会信用代码,含末位校验码验证。字母不区分大小写,且自动排除易混淆的 IOSVZ

isUsci("91350100M000100Y43"); // true
isUsci("91350100m000100y43"); // true,忽略大小写

isUsci("91350100M000100Y44"); // false,校验码错误
isUsci("91350100I000100Y43"); // false,含非法字符 I

isPassword

isPassword(value: unknown, options?: PasswordOptions): boolean;

type PasswordOptions = {
  alpha?: boolean; // 是否必须含字母,默认 true
  sensitive?: boolean; // 是否必须同时含大小写字母,默认 false
  number?: boolean; // 是否必须含数字,默认 true
  special?: string; // 允许且必须出现的特殊字符集,默认 SPECIAL_CHARS
  min?: number; // 最小长度,默认 8
  max?: number; // 最大长度,默认 16
};

按长度和字符组成规则校验密码。密码只能由字母、数字和 special 中的字符构成,出现其他字符(如中文)一律不通过。

alphanumberspecial 都是双向约束:设为 true(或非空字符串)表示必须包含,设为 false(或空字符串)表示必须不包含

isPassword("Abcd123!"); // true

isPassword("abcd1234"); // false,默认要求包含特殊字符
isPassword("abcd1234", { special: "" }); // true,关闭特殊字符要求
isPassword("abcd123!中"); // false,含允许范围外的字符

isPassword("abcd123!", { sensitive: true }); // false,缺少大写字母
isPassword("Abcd123!", { sensitive: true }); // true

isPassword("abc1!", { min: 4, max: 8 }); // true,自定义长度区间
isPassword("12345678", { alpha: false, special: "" }); // true,纯数字密码

格式化

separator

separator(value: unknown, sign?: string, length?: number, reverse?: boolean): string;
// sign 默认 " ",length 默认 4,reverse 默认 false

将值的字符串形式按固定长度分组并插入分隔符。reversetrue 时从右往左分组,适合数字场景。length 非正整数时回退为 4

separator("1234567890"); // "1234 5678 90"
separator("1234567890", "-"); // "1234-5678-90"
separator("1234567890", " ", 3); // "123 456 789 0"

separator("1234567890", " ", 4, true); // "12 3456 7890",从右往左
separator(1234567890, ",", 3, true); // "1,234,567,890"

thousand

thousand(value: unknown, currency?: string, fixed?: number): string;
// currency 默认 ""

按千分位格式化数值,可附加货币符号并固定小数位数。非数值返回空字符串。fixed 需为非负整数,否则忽略并保留原有小数位。负号位于货币符号之前。

thousand(1234567.891); // "1,234,567.891"
thousand(1234567.891, "¥"); // "¥1,234,567.891"
thousand(1234567.891, "¥", 2); // "¥1,234,567.89"
thousand("1234.5", "", 0); // "1,235"
thousand(-1234.5, "$", 2); // "-$1,234.50"

thousand("abc"); // ""
thousand(null); // ""

注意:固定使用 en-US 千分位规则;数值经 Number 转换,超大数可能损失精度。

decimal

decimal(value: unknown, scale?: number, fixed?: number): string;
// scale 默认 0

10^scale 缩放十进制值并返回字符串,即结果为 value × 10^scale。内部使用 BigInt 计算,不受浮点误差影响,适合金额分/元换算。

fixed 指定保留的小数位数,省略时保留缩放后的原始精度。舍入方式为远离零方向的四舍五入。无法解析的值返回空字符串。

decimal("1.23", 2); // "123",元转分
decimal("123", -2); // "1.23",分转元
decimal(12.3456); // "12.3456",保留原始精度

decimal("1.239", 0, 2); // "1.24"
decimal("1.235", 0, 2); // "1.24",远离零方向舍入
decimal("-1.235", 0, 2); // "-1.24"
decimal("1.005", 0, 2); // "1.01",不受浮点误差影响
decimal(0.1 + 0.2, 0, 2); // "0.30"

decimal("1e3"); // "1000",支持科学计数法
decimal("abc"); // ""

formatSize

formatSize(value: unknown, from?: SizeUnit, to?: SizeUnit, fixed?: number): string;
// from 默认 "B",fixed 默认 2

type SizeUnit = "B" | "KB" | "MB" | "GB" | "TB";

按 1024 进制在字节单位之间换算,返回带单位的字符串(数值与单位间有一个空格)。省略 to 时自动选取使数值落在 [1, 1024) 的单位,上下限为 BTB

fixed 为保留的小数位数,采用 toFixed 的四舍五入。值无法转为有限数值、单位不在枚举内、或 fixed 不是 0~100 的整数时返回空字符串。

formatSize(1536); // "1.50 KB",自动选取单位
formatSize(1048576); // "1.00 MB"
formatSize(0); // "0.00 B"

formatSize(1536, "B", "KB"); // "1.50 KB"
formatSize(1, "GB", "MB"); // "1024.00 MB"
formatSize(2, "KB", "GB"); // "0.00 GB",指定目标单位时不做上下限调整

formatSize(1536, "B", "KB", 0); // "2 KB"
formatSize(1.5, "MB", undefined, 3); // "1.500 MB"
formatSize(1023.999); // "1.00 KB",进位后自动切换单位

formatSize(1536, "b"); // "",单位大小写敏感
formatSize("abc"); // ""

注意:使用 1024 进制和 KB/MB 记法(即通常所说的 KiB/MiB),不支持 1000 进制的硬盘厂商口径。

asterisk

asterisk(value: unknown, start?: number, end?: number, sign?: string): string;
// start 默认 0,sign 默认 "*"

将字符串 [start, end) 区间内的字符替换为掩码符号,区间语义与 String.prototype.slice 一致,省略 end 表示到字符串末尾。非字符串返回空字符串;sign 为空字符串时原样返回。

asterisk("13800138000", 3, 7); // "138****8000"
asterisk("abcdef", 1, 3); // "a**def"
asterisk("abcdef", 1, 3, "#"); // "a##def"

asterisk("abcdef"); // "******",全部替换
asterisk("abcdef", 2); // "ab****",从下标 2 到末尾
asterisk("abcdef", -2); // "abcd**",负数下标从末尾计算

asterisk("abcdef", 10); // "abcdef",区间为空时原样返回
asterisk(123456, 1, 3); // "",非字符串

注意:按 UTF-16 码元计数,emoji 等字符可能被截断。

display

display(value: unknown, unit?: string, empty?: string): string;
// empty 默认 "-"

用于展示层的空值兜底:值为空时返回占位符,否则转为字符串并追加单位。空值判定复用 isEmpty

display("abc"); // "abc"
display(12, "元"); // "12元"
display(0, "元"); // "0元",0 不算空

display(null); // "-"
display(undefined, "元"); // "-",占位时不追加单位
display("", "", "暂无"); // "暂无"
display([], "", "空"); // "空"

解析

parseIdNo

parseIdNo(value: unknown): IdNoInfo | null;

type IdNoInfo = {
  gender: "male" | "female"; // 性别,由顺序码奇偶决定
  birthday: string; // 出生日期,格式为 YYYY-MM-DD
  region: string; // 6 位行政区划代码
};

从中国大陆 18 位居民身份证号码中提取性别、出生日期和地区码。解析前先用 isIdNo 校验,号码非法时返回 null

parseIdNo("11010519491231002X");
// { gender: "female", birthday: "1949-12-31", region: "110105" }

parseIdNo("110105194912310011");
// { gender: "male", birthday: "1949-12-31", region: "110105" }

parseIdNo("110105194912310021"); // null,校验码错误
parseIdNo(undefined); // null

注意:只返回 6 位地区码本身,不含省市区名称;行政区划代码会随区划调整变更,历史号码可能对应已撤销的代码。


对象

merge

merge<T extends Mergeable>(target: T, ...sources: (Mergeable | undefined)[]): T;

type Mergeable = Record<PropertyKey, unknown> | unknown[];

深度合并多个对象或数组,返回全新的值,不修改任何入参。

合并规则:两侧同为普通对象时逐键递归;同为数组时按下标合并;其余情况后者整体覆盖前者。sources 中的 undefined 会被跳过。已内置原型链污染防护,__proto__constructorprototype 键会被忽略。

merge({ a: { b: 1 } }, { a: { c: 2 } }); // { a: { b: 1, c: 2 } }
merge({ a: 1 }, { a: 2 }, { a: 3 }); // { a: 3 }
merge({ a: [1, 2, 3] }, { a: [9] }); // { a: [9, 2, 3] },数组按下标合并
merge({ a: 1 }, undefined, { b: 2 }); // { a: 1, b: 2 },跳过 undefined 源

// 深拷贝,修改结果不影响源对象
const source = { a: { b: 1 } };
const result = merge({}, source);
result.a.b = 99;
source.a.b; // 1

注意:跳过的只是整个为 undefined 的源对象;源对象内部的 undefined 属性值仍会覆盖已有值,merge({ a: 1 }, { a: undefined }) 得到 { a: undefined }


文件

getMimeType

getMimeType(value: unknown): string;

根据文件名或后缀查询 MIME 类型,取最后一个 . 之后的部分并忽略大小写。未收录的后缀返回空字符串。完整映射表见常量 MIME_TYPES

getMimeType("a.pdf"); // "application/pdf"
getMimeType(".png"); // "image/png"
getMimeType("PNG"); // "image/png",可直接传后缀
getMimeType("a.tar.gz"); // "application/gzip",只取最后一段

getMimeType("a.xyz"); // ""
getMimeType(123); // ""

base64ToDataUrl

base64ToDataUrl(value: string, name?: string): string;

将 Base64 字符串拼接为 Data URL。MIME 类型由 name(文件名或后缀)推断,无法识别或未传时回退为 image/png。传入的已经是 Data URL 时原样返回,不会重复添加前缀。

base64ToDataUrl("aGVsbG8=", "a.pdf"); // "data:application/pdf;base64,aGVsbG8="
base64ToDataUrl("aGVsbG8=", "png"); // "data:image/png;base64,aGVsbG8="

base64ToDataUrl("aGVsbG8="); // "data:image/png;base64,aGVsbG8=",回退默认类型
base64ToDataUrl("aGVsbG8=", "a.xyz"); // "data:image/png;base64,aGVsbG8="

base64ToDataUrl("data:image/webp;base64,aGVsbG8=", "a.pdf");
// "data:image/webp;base64,aGVsbG8=",已是 Data URL 时原样返回

bytesToBase64

bytesToBase64(data: Uint8Array): string;

将字节数组编码为 Base64 字符串。内部分块处理,可安全处理大数组而不会栈溢出。

bytesToBase64(new Uint8Array([104, 101, 108, 108, 111])); // "aGVsbG8="

base64ToBytes

base64ToBytes(base64: string): Uint8Array<ArrayBuffer>;

将 Base64 字符串解码为字节数组。入参需为纯 Base64,不接受 Data URL 前缀。

base64ToBytes("aGVsbG8="); // Uint8Array [104, 101, 108, 108, 111]

注意:非法 Base64 会让底层 atob 抛出异常。

base64ToFile

base64ToFile(value: string, name: string): File;

将 Base64 或 Data URL 转换为 File 对象。MIME 类型优先取自 Data URL 中声明的类型,其次由文件名推断,都不可用时回退为 image/png

base64ToFile("aGVsbG8=", "a.png");
// File { name: "a.png", type: "image/png", size: 5 }

base64ToFile("data:image/webp;base64,aGVsbG8=", "a.png");
// File { name: "a.png", type: "image/webp" },Data URL 中的类型优先

base64ToFile("aGVsbG8=", "a.xyz");
// File { name: "a.xyz", type: "image/png" },回退默认类型

blobToFile

blobToFile(blob: Blob, name: string): File;

Blob 补上文件名转换成 File,常用于处理 fetchcanvas.toBlob 的结果。MIME 类型优先取自 blob.type,其次由文件名推断,都不可用时回退为 image/png

blobToFile(new Blob(["hello"], { type: "image/webp" }), "a.pdf");
// File { name: "a.pdf", type: "image/webp" },blob.type 优先

blobToFile(new Blob(["hello"]), "a.pdf");
// File { name: "a.pdf", type: "application/pdf" },由文件名推断

blobToFile(new Blob(["hello"]), "a.xyz");
// File { name: "a.xyz", type: "image/png" },回退默认类型

downloadFile

downloadFile(url: string, name: string): void;

触发浏览器下载:创建隐藏的 <a download> 并自动点击,结束后移除。url 可以是普通链接、Data URL 或 URL.createObjectURL 生成的地址。

downloadFile("https://example.com/report.pdf", "报表.pdf");

// 配合 Blob 使用
const url = URL.createObjectURL(new Blob(["a,b\n1,2"], { type: "text/csv" }));
downloadFile(url, "data.csv");
URL.revokeObjectURL(url);

注意:仅可在浏览器环境调用。跨域地址的 download 属性会被浏览器忽略,此时通常会直接打开而非下载。

zipFiles

zipFiles(files: File | File[], zipName?: string): Promise<File>;
// zipName 默认 "files.zip"

将单个或多个 File 打包成一个 ZIP File(类型为 application/zip)。条目名取自 file.name,重名时在扩展名前追加 (1)(2) 序号,文件名为空时回退为 file-1。名称中的 / 会在 ZIP 内形成目录层级。

// 单个文件,无需包成数组
await zipFiles(new File(["hello"], "a.txt"));
// File { name: "files.zip", type: "application/zip" }

await zipFiles([new File(["a"], "a.txt"), new File(["b"], "b.txt")], "包.zip");
// File { name: "包.zip" },内含 a.txt、b.txt

// 重名自动去重
await zipFiles([new File(["a"], "a.png"), new File(["b"], "a.png")]);
// 内含 a.png、a (1).png

// 配合 downloadFile 直接下载
const pack = await zipFiles(files);
const url = URL.createObjectURL(pack);
downloadFile(url, pack.name);
URL.revokeObjectURL(url);

unzipFiles

unzipFiles(zipFile: File | Blob): Promise<File[]>;

将 ZIP 解压成 File 数组,目录条目会被跳过。文件名保留 ZIP 内的相对路径(如 dir/a.txt),MIME 类型由该路径推断,无法识别时为空字符串。

await unzipFiles(new File([bytes], "pack.zip"));
// [File { name: "a.txt", type: "text/plain" }, File { name: "dir/b.pdf", type: "application/pdf" }]

// 也接受 Blob,可直接处理 fetch 结果
await unzipFiles(await (await fetch("/pack.zip")).blob());

注意zipFilesunzipFiles 基于 fflate,已作为依赖随包安装,无需额外引入。传入非法 ZIP 数据时 unzipFiles 会 reject(invalid zip data)。两者都会把整包读入内存,超大文件请谨慎使用。


DOM

openWithForm

openWithForm(url: string, data?: Record<string, FormValue>, method?: "POST" | "GET"): void;
// data 默认 {},method 默认 "POST"

以动态表单的方式跳转到目标地址,适用于需要携带参数、又无法用普通链接表达的页面跳转。

参数值会被序列化为隐藏域:对象序列化为 JSON 字符串,其他类型转为字符串,值为 nullundefined 的字段会被跳过。

openWithForm("https://example.com/pay", {
  orderNo: "202601010001",
  amount: 100,
  extra: { source: "web" }, // 自动 JSON.stringify
  remark: null, // 跳过,不生成隐藏域
});

openWithForm("https://example.com/search", { keyword: "abc" }, "GET");

注意:仅可在浏览器环境调用。

loadScript

loadScript(url: string, attributes?: ScriptAttributes): Promise<void>;
// attributes 默认 {}

type ScriptAttributes = Record<string, string | number | boolean | null | undefined>;

创建 script 标签并插入 document.head 来加载远程脚本,适合按需加载第三方 SDK。onload 后 resolve,标签保留在页面上;onerror 后先移除标签再 reject。

attributes 会通过 setAttribute 写到标签上:值为 true 时作为布尔属性写入(如 async),值为 falsenullundefined 的项会被跳过,其余转为字符串。async 默认为 true,传 async: false 可关闭。src 始终取自 url,不会被 attributes 覆盖。

// 加载成功后 resolve,标签保留在页面上;默认带 async
await loadScript("https://cdn.example.com/sdk.js"); // <script async src="..."></script>

// 传入标签属性
await loadScript("https://cdn.example.com/sdk.js", {
  crossorigin: "anonymous",
  "data-app-id": 10086,
});

// 关闭默认的 async
await loadScript("https://cdn.example.com/sdk.js", { async: false, defer: true });

// 加载失败时 reject,并同时移除标签
try {
  await loadScript("https://cdn.example.com/404.js");
} catch (error) {
  console.error(error); // Error: Failed to load script: https://cdn.example.com/404.js
}

注意:仅可在浏览器环境调用。不会对相同 url 去重,重复调用会插入多个标签。


常量

| 常量 | 值 | 说明 | | ------------------ | --------------------------------- | ---------------------------- | | MONTH_FORMAT | "YYYY-MM" | 月份格式 | | DATE_FORMAT | "YYYY-MM-DD" | 日期格式 | | TIME_FORMAT | "HH:mm:ss" | 时间格式 | | DATE_TIME_FORMAT | "YYYY-MM-DD HH:mm:ss" | 日期时间格式 | | LONG_DATE | Date | 长期有效日期,9999-12-31 | | LONG_DATE_LABEL | "长期" | 长期有效的展示文案 | | MIN_DATE | Date | 日期选择下限,1900-01-01 | | MAX_DATE | Date | 日期选择上限,2099-12-31 | | SPECIAL_CHARS | "!@#$%^&*()-=_+[]\\\|{},./?<>~" | 密码默认允许的特殊字符集 | | MIME_TYPES | Record<string, string> | 常见后缀到 MIME 类型的映射表 | | PALETTE | Record<string, string> | 图表配色用的调色板 |

import { DATE_FORMAT, LONG_DATE, MIME_TYPES, PALETTE } from "@bigflower/utils";

DATE_FORMAT; // "YYYY-MM-DD"
LONG_DATE; // Date 9999-12-31
MIME_TYPES.pdf; // "application/pdf"
PALETTE.bananaRed; // "#D4042D"
Object.values(PALETTE); // 按顺序取色,适合图表系列配色

PALETTE 共 8 色,键为驼峰色名,值为十六进制色值:

| 键 | 色值 | 中文名 | | ---------------- | --------- | -------- | | bananaRed | #D4042D | 蕉红 | | sunlitOrange | #DB7A0E | 暖阳橙 | | cornflowerBlue | #5A92E5 | 矢车菊蓝 | | emeraldMist | #5E8034 | 翠微 | | merlotPink | #EB6D98 | 梅洛粉 | | jadeCyan | #41B5C2 | 碧青 | | lemonYellow | #FACA2E | 柠檬黄 | | royalPurple | #722169 | 皇家紫 |

注意LONG_DATEMIN_DATEMAX_DATE 是共享的 Date 实例,请勿直接修改,需要变更时先复制一份。MIME_TYPESPALETTE 都用 as const 声明,取值为字面量类型且属性只读。


开发

pnpm install
pnpm build
pnpm lint

发布

pnpm publish