@nickyzj2023/utils 1.0.57 → 1.0.58
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{index.d.ts → index.d.mts} +109 -81
- package/dist/index.mjs +2 -0
- package/package.json +15 -15
- package/dist/index.js +0 -2
|
@@ -1,17 +1,18 @@
|
|
|
1
|
+
//#region src/dom/log.d.ts
|
|
1
2
|
/**
|
|
2
3
|
* log 配置选项
|
|
3
4
|
*/
|
|
4
5
|
interface LogOptions {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
6
|
+
/**
|
|
7
|
+
* 是否显示时间
|
|
8
|
+
* @default true
|
|
9
|
+
*/
|
|
10
|
+
time?: boolean;
|
|
11
|
+
/**
|
|
12
|
+
* 是否显示调用者文件名
|
|
13
|
+
* @default true
|
|
14
|
+
*/
|
|
15
|
+
fileName?: boolean;
|
|
15
16
|
}
|
|
16
17
|
/**
|
|
17
18
|
* 带额外信息的 console.log
|
|
@@ -26,7 +27,8 @@ interface LogOptions {
|
|
|
26
27
|
* log(["消息1", "消息2"]); // "[14:30:00] [index.ts:15] 消息1 消息2"
|
|
27
28
|
*/
|
|
28
29
|
declare const log: (message: any | any[], options?: LogOptions) => void;
|
|
29
|
-
|
|
30
|
+
//#endregion
|
|
31
|
+
//#region src/function/loop-until.d.ts
|
|
30
32
|
/**
|
|
31
33
|
* 循环执行函数,直到符合停止条件
|
|
32
34
|
*
|
|
@@ -55,15 +57,15 @@ declare const log: (message: any | any[], options?: LogOptions) => void;
|
|
|
55
57
|
* ),
|
|
56
58
|
*/
|
|
57
59
|
declare const loopUntil: <T>(fn: (count: number) => T | Promise<T>, options?: {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
shouldStop?: (result: T) => boolean;
|
|
60
|
+
/**
|
|
61
|
+
* 最大循环次数
|
|
62
|
+
* @default 5
|
|
63
|
+
*/
|
|
64
|
+
maxRetries?: number; /** 停止循环条件。如果未传递,则执行 maxRetries 次后退出并返回最后结果 */
|
|
65
|
+
shouldStop?: (result: T) => boolean;
|
|
65
66
|
}) => Promise<T>;
|
|
66
|
-
|
|
67
|
+
//#endregion
|
|
68
|
+
//#region src/hoc/with-cache.d.ts
|
|
67
69
|
type SetTtl = (seconds: number) => void;
|
|
68
70
|
/**
|
|
69
71
|
* 创建一个带缓存的高阶函数
|
|
@@ -100,13 +102,14 @@ type SetTtl = (seconds: number) => void;
|
|
|
100
102
|
* await fetchData(urlB); // 使用缓存结果
|
|
101
103
|
*/
|
|
102
104
|
declare const withCache: <Args extends any[], Result>(fn: (this: {
|
|
103
|
-
|
|
105
|
+
setTtl: SetTtl;
|
|
104
106
|
}, ...args: Args) => Result, ttlSeconds?: number) => {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
107
|
+
(...args: Args): Result;
|
|
108
|
+
clear(): void;
|
|
109
|
+
updateTtl(seconds: number): void;
|
|
108
110
|
};
|
|
109
|
-
|
|
111
|
+
//#endregion
|
|
112
|
+
//#region src/is/is-falsy.d.ts
|
|
110
113
|
type Falsy = false | 0 | -0 | 0n | "" | null | undefined;
|
|
111
114
|
/**
|
|
112
115
|
* 检测传入的值是否为**假值**(false、0、''、null、undefined、NaN等)
|
|
@@ -116,7 +119,8 @@ type Falsy = false | 0 | -0 | 0n | "" | null | undefined;
|
|
|
116
119
|
* isFalsy(1); // false
|
|
117
120
|
*/
|
|
118
121
|
declare const isFalsy: (value: any) => value is Falsy;
|
|
119
|
-
|
|
122
|
+
//#endregion
|
|
123
|
+
//#region src/is/is-nil.d.ts
|
|
120
124
|
/**
|
|
121
125
|
* 检测传入的值是否为**空值**(null、undefined)
|
|
122
126
|
*
|
|
@@ -126,7 +130,8 @@ declare const isFalsy: (value: any) => value is Falsy;
|
|
|
126
130
|
* isNil(1); // false
|
|
127
131
|
*/
|
|
128
132
|
declare const isNil: (value: any) => value is null | undefined;
|
|
129
|
-
|
|
133
|
+
//#endregion
|
|
134
|
+
//#region src/is/is-object.d.ts
|
|
130
135
|
/**
|
|
131
136
|
* 检测传入的值是否为**普通对象**
|
|
132
137
|
*
|
|
@@ -135,7 +140,8 @@ declare const isNil: (value: any) => value is null | undefined;
|
|
|
135
140
|
* isObject(obj); // true
|
|
136
141
|
*/
|
|
137
142
|
declare const isObject: (value: any) => value is Record<string, any>;
|
|
138
|
-
|
|
143
|
+
//#endregion
|
|
144
|
+
//#region src/is/is-primitive.d.ts
|
|
139
145
|
type Primitive = number | string | boolean | symbol | bigint | undefined | null;
|
|
140
146
|
/**
|
|
141
147
|
* 检测传入的值是否为**原始值**(number、string、boolean、symbol、bigint、undefined、null)
|
|
@@ -145,14 +151,14 @@ type Primitive = number | string | boolean | symbol | bigint | undefined | null;
|
|
|
145
151
|
* isPrimitive([]); // false
|
|
146
152
|
*/
|
|
147
153
|
declare const isPrimitive: (value: any) => value is Primitive;
|
|
148
|
-
|
|
154
|
+
//#endregion
|
|
155
|
+
//#region src/network/fetcher.d.ts
|
|
149
156
|
type FetchOptions = {
|
|
150
|
-
|
|
151
|
-
proxy?: string;
|
|
157
|
+
/** 代理服务器配置 */proxy?: string;
|
|
152
158
|
};
|
|
153
159
|
type RequestInit = globalThis.RequestInit & FetchOptions & {
|
|
154
|
-
|
|
155
|
-
|
|
160
|
+
params?: Record<string, any>;
|
|
161
|
+
parser?: (response: Response) => Promise<any>;
|
|
156
162
|
};
|
|
157
163
|
/**
|
|
158
164
|
* 基于 Fetch API 的请求客户端
|
|
@@ -197,36 +203,37 @@ type RequestInit = globalThis.RequestInit & FetchOptions & {
|
|
|
197
203
|
* await getBlogs("/blogs"); // 不发请求,使用缓存
|
|
198
204
|
*/
|
|
199
205
|
declare const fetcher: (baseURL?: string, baseOptions?: RequestInit) => {
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
206
|
+
get: <T>(url: string, options?: Omit<RequestInit, "method">) => Promise<T>;
|
|
207
|
+
post: <T>(url: string, body: any, options?: Omit<RequestInit, "method" | "body">) => Promise<T>;
|
|
208
|
+
put: <T>(url: string, body: any, options?: Omit<RequestInit, "method" | "body">) => Promise<T>;
|
|
209
|
+
delete: <T>(url: string, options?: Omit<RequestInit, "method" | "body">) => Promise<T>;
|
|
204
210
|
};
|
|
205
|
-
|
|
211
|
+
//#endregion
|
|
212
|
+
//#region src/network/get-real-url.d.ts
|
|
206
213
|
/** 从 url 响应头获取真实链接 */
|
|
207
214
|
declare const getRealURL: (originURL: string) => Promise<string>;
|
|
208
|
-
|
|
215
|
+
//#endregion
|
|
216
|
+
//#region src/network/image.d.ts
|
|
209
217
|
/**
|
|
210
218
|
* 图片压缩选项
|
|
211
219
|
*/
|
|
212
220
|
type ImageCompressionOptions = {
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
fetcher?: (url: string) => Promise<Response>;
|
|
221
|
+
/** 压缩比率,默认 0.92 */quality?: number;
|
|
222
|
+
/**
|
|
223
|
+
* 自定义压缩函数,用于覆盖默认压缩行为
|
|
224
|
+
* @param arrayBuffer 图片的 ArrayBuffer 数据
|
|
225
|
+
* @param mime 图片的 MIME 类型
|
|
226
|
+
* @param quality 压缩质量
|
|
227
|
+
* @returns 压缩后的 base64 字符串
|
|
228
|
+
*/
|
|
229
|
+
compressor?: (arrayBuffer: ArrayBuffer, mime: string, quality: number) => Promise<string> | string;
|
|
230
|
+
/**
|
|
231
|
+
* 自定义 fetch 函数,用于使用自己封装的请求库读取图片
|
|
232
|
+
* 必须返回符合 Web 标准的 Response 对象
|
|
233
|
+
* @param url 图片地址
|
|
234
|
+
* @returns Promise<Response>
|
|
235
|
+
*/
|
|
236
|
+
fetcher?: (url: string) => Promise<Response>;
|
|
230
237
|
};
|
|
231
238
|
/**
|
|
232
239
|
* 图片地址转 base64 数据
|
|
@@ -265,7 +272,8 @@ type ImageCompressionOptions = {
|
|
|
265
272
|
* });
|
|
266
273
|
*/
|
|
267
274
|
declare const imageUrlToBase64: (imageUrl: string, options?: ImageCompressionOptions) => Promise<string>;
|
|
268
|
-
|
|
275
|
+
//#endregion
|
|
276
|
+
//#region src/network/to.d.ts
|
|
269
277
|
/**
|
|
270
278
|
* Go 语言风格的异步处理方式
|
|
271
279
|
* @param promise 一个能被 await 的异步函数
|
|
@@ -275,7 +283,8 @@ declare const imageUrlToBase64: (imageUrl: string, options?: ImageCompressionOpt
|
|
|
275
283
|
* const [error, response] = await to(fetcher().get<Blog>("/blogs/hello-world"));
|
|
276
284
|
*/
|
|
277
285
|
declare const to: <T, E = Error>(promise: Promise<T>) => Promise<[null, T] | [E, undefined]>;
|
|
278
|
-
|
|
286
|
+
//#endregion
|
|
287
|
+
//#region src/number/random-int.d.ts
|
|
279
288
|
/**
|
|
280
289
|
* 在指定闭区间内生成随机整数
|
|
281
290
|
*
|
|
@@ -283,9 +292,10 @@ declare const to: <T, E = Error>(promise: Promise<T>) => Promise<[null, T] | [E,
|
|
|
283
292
|
* randomInt(1, 10); // 1 <= x <= 10
|
|
284
293
|
*/
|
|
285
294
|
declare const randomInt: (min: number, max: number) => number;
|
|
286
|
-
|
|
295
|
+
//#endregion
|
|
296
|
+
//#region src/object/map-keys.d.ts
|
|
287
297
|
type DeepMapKeys<T> = T extends Array<infer U> ? Array<DeepMapKeys<U>> : T extends object ? {
|
|
288
|
-
|
|
298
|
+
[key: string]: DeepMapKeys<T[keyof T]>;
|
|
289
299
|
} : T;
|
|
290
300
|
/**
|
|
291
301
|
* 递归处理对象里的 key
|
|
@@ -301,10 +311,9 @@ type DeepMapKeys<T> = T extends Array<infer U> ? Array<DeepMapKeys<U>> : T exten
|
|
|
301
311
|
* console.log(result); // { A: { B: 1 } }
|
|
302
312
|
*/
|
|
303
313
|
declare const mapKeys: <T>(obj: T, getNewKey: (key: string) => string) => DeepMapKeys<T>;
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
} : R;
|
|
314
|
+
//#endregion
|
|
315
|
+
//#region src/object/map-values.d.ts
|
|
316
|
+
type DeepMapValues<T, R> = T extends Array<infer U> ? Array<DeepMapValues<U, R>> : T extends object ? { [K in keyof T]: T[K] extends object ? DeepMapValues<T[K], R> : R } : R;
|
|
308
317
|
/**
|
|
309
318
|
* 递归处理对象里的 value
|
|
310
319
|
*
|
|
@@ -320,10 +329,10 @@ type DeepMapValues<T, R> = T extends Array<infer U> ? Array<DeepMapValues<U, R>>
|
|
|
320
329
|
* console.log(result); // { a: 2, b: { c: 3 } }
|
|
321
330
|
*/
|
|
322
331
|
declare const mapValues: <T, R = any>(obj: T, getNewValue: (value: any, key: string | number) => R, options?: {
|
|
323
|
-
|
|
324
|
-
filter?: (value: any, key: string | number) => boolean;
|
|
332
|
+
/** 过滤函数,返回 true 表示保留该字段 */filter?: (value: any, key: string | number) => boolean;
|
|
325
333
|
}) => DeepMapValues<T, R>;
|
|
326
|
-
|
|
334
|
+
//#endregion
|
|
335
|
+
//#region src/object/merge-objects.d.ts
|
|
327
336
|
/**
|
|
328
337
|
* 深度合并两个对象,规则如下:
|
|
329
338
|
* 1. 原始值覆盖:如果两个值都是原始类型,则用后者覆盖;
|
|
@@ -336,7 +345,8 @@ declare const mapValues: <T, R = any>(obj: T, getNewValue: (value: any, key: str
|
|
|
336
345
|
* @param {U} obj2 要合并的第二个对象
|
|
337
346
|
*/
|
|
338
347
|
declare const mergeObjects: <T extends Record<string, any>, U extends Record<string, any>>(obj1: T, obj2: U) => T & U;
|
|
339
|
-
|
|
348
|
+
//#endregion
|
|
349
|
+
//#region src/string/case.d.ts
|
|
340
350
|
type SnakeToCamel<S extends string> = S extends `${infer Before}_${infer After}` ? After extends `${infer First}${infer Rest}` ? `${Before}${Uppercase<First>}${SnakeToCamel<Rest>}` : Before : S;
|
|
341
351
|
/**
|
|
342
352
|
* 下划线命名法转为驼峰命名法
|
|
@@ -369,7 +379,8 @@ type Decapitalize<S extends string> = S extends `${infer P1}${infer Rest}` ? P1
|
|
|
369
379
|
* decapitalize("Hello") // "hello"
|
|
370
380
|
*/
|
|
371
381
|
declare const decapitalize: <S extends string>(s: S) => Decapitalize<S>;
|
|
372
|
-
|
|
382
|
+
//#endregion
|
|
383
|
+
//#region src/string/compact.d.ts
|
|
373
384
|
/**
|
|
374
385
|
* 将字符串压缩为单行精简格式
|
|
375
386
|
*
|
|
@@ -383,16 +394,31 @@ declare const decapitalize: <S extends string>(s: S) => Decapitalize<S>;
|
|
|
383
394
|
* });
|
|
384
395
|
*/
|
|
385
396
|
declare const compactStr: (text?: string, options?: {
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
/** 是否合并连续的空格/制表符为一个空格,默认开启 */
|
|
391
|
-
disableWhitespaceCollapse?: boolean;
|
|
392
|
-
/** 截断后的后缀,默认为 "..." */
|
|
393
|
-
omission?: string;
|
|
397
|
+
/** 最大保留长度,设为 0 或 Infinity 则不截断,默认 Infinity */maxLength?: number; /** 是否将换行符替换为字面量 \n,默认开启 */
|
|
398
|
+
disableNewLineReplace?: boolean; /** 是否合并连续的空格/制表符为一个空格,默认开启 */
|
|
399
|
+
disableWhitespaceCollapse?: boolean; /** 截断后的后缀,默认为 "..." */
|
|
400
|
+
omission?: string;
|
|
394
401
|
}) => string;
|
|
395
|
-
|
|
402
|
+
//#endregion
|
|
403
|
+
//#region src/string/qs.d.ts
|
|
404
|
+
/**
|
|
405
|
+
* 针对 URL 查询字符串的解析和序列化
|
|
406
|
+
* @example
|
|
407
|
+
* qs.parse("?a=1&b=2") // { a: 1, b: 2 }
|
|
408
|
+
* qs.stringify({ a: 1, b: 2 }, { addQueryPrefix: true }) // "?a=1&b=2"
|
|
409
|
+
*/
|
|
410
|
+
declare const qs: {
|
|
411
|
+
/** queryString -> queryParams */parse: (queryString: string) => Record<string, any>;
|
|
412
|
+
stringify: (params: Record<string, any>, options?: {
|
|
413
|
+
/**
|
|
414
|
+
* 是否在结果前添加“?”
|
|
415
|
+
* @default false
|
|
416
|
+
*/
|
|
417
|
+
addQueryPrefix: boolean;
|
|
418
|
+
}) => string;
|
|
419
|
+
};
|
|
420
|
+
//#endregion
|
|
421
|
+
//#region src/time/debounce.d.ts
|
|
396
422
|
/**
|
|
397
423
|
* 防抖:在指定时间内只执行最后一次调用
|
|
398
424
|
* @param fn 要防抖的函数
|
|
@@ -413,7 +439,8 @@ declare const compactStr: (text?: string, options?: {
|
|
|
413
439
|
* search('hello'); // 300ms 后执行
|
|
414
440
|
*/
|
|
415
441
|
declare const debounce: <T extends (...args: any[]) => any>(fn: T, delay?: number) => (...args: Parameters<T>) => void;
|
|
416
|
-
|
|
442
|
+
//#endregion
|
|
443
|
+
//#region src/time/sleep.d.ts
|
|
417
444
|
/**
|
|
418
445
|
* 延迟一段时间再执行后续代码
|
|
419
446
|
* @param time 延迟时间,默认 150ms
|
|
@@ -421,7 +448,8 @@ declare const debounce: <T extends (...args: any[]) => any>(fn: T, delay?: numbe
|
|
|
421
448
|
* await sleep(1000); // 等待 1 秒执行后续代码
|
|
422
449
|
*/
|
|
423
450
|
declare const sleep: (time?: number) => Promise<unknown>;
|
|
424
|
-
|
|
451
|
+
//#endregion
|
|
452
|
+
//#region src/time/throttle.d.ts
|
|
425
453
|
/**
|
|
426
454
|
* 节流函数 - 在指定时间间隔内最多执行一次调用
|
|
427
455
|
* @param fn 要节流的函数
|
|
@@ -442,5 +470,5 @@ declare const sleep: (time?: number) => Promise<unknown>;
|
|
|
442
470
|
* window.addEventListener('scroll', handleScroll);
|
|
443
471
|
*/
|
|
444
472
|
declare const throttle: <T extends (...args: any[]) => any>(fn: T, delay?: number) => (this: any, ...args: Parameters<T>) => void;
|
|
445
|
-
|
|
446
|
-
export {
|
|
473
|
+
//#endregion
|
|
474
|
+
export { CamelToSnake, Capitalize, Decapitalize, DeepMapKeys, DeepMapValues, Falsy, FetchOptions, ImageCompressionOptions, LogOptions, Primitive, RequestInit, SetTtl, SnakeToCamel, camelToSnake, capitalize, compactStr, debounce, decapitalize, fetcher, getRealURL, imageUrlToBase64, isFalsy, isNil, isObject, isPrimitive, log, loopUntil, mapKeys, mapValues, mergeObjects, qs, randomInt, sleep, snakeToCamel, throttle, to, withCache };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=(e,t)=>{let{time:n=!0,fileName:r=!0}=t??{},i=[];if(n&&i.push(`[${new Date().toLocaleTimeString()}]`),r){let{stack:e}=Error(),t=(e?.split(`
|
|
2
|
+
`)[2]?.trim())?.match(/at\s+(.*):(\d+)/);if(t?.[1]){let e=t[1].split(/[/\\]/).pop();i.push(`[${e}:${t[2]}]`)}}Array.isArray(e)?i.push(...e):i.push(e),console.log(...i)},t=async(e,t)=>{let{maxRetries:n=5,shouldStop:r}=t??{},i;for(let t=0;t<n;t++)if(i=await e(t),r?.(i)===!0)return i;if(!r)return i;throw Error(`超过了最大循环次数(${n})且未满足停止执行条件`)},n=(e,t=-1)=>{let n=new Map,r=(...r)=>{let i=JSON.stringify(r),a=Date.now(),o=n.get(i);if(o&&a<o.expiresAt)return o.value;let s=t===-1?1/0:a+t*1e3,c=e.apply({setTtl:e=>{s=a+e*1e3}},r);if(c instanceof Promise){let e=c.then(e=>(n.set(i,{value:e,expiresAt:s}),e));return n.set(i,{value:e,expiresAt:s}),e}return n.set(i,{value:c,expiresAt:s}),c};return r.clear=()=>n.clear(),r.updateTtl=e=>{t=e;let r=Date.now(),i=r+e*1e3;for(let[e,t]of n.entries())t.expiresAt>r&&(t.expiresAt=i,n.set(e,t))},r},r=e=>!e,i=e=>e==null,a=e=>e?.constructor===Object,o=e=>e==null||typeof e!=`object`&&typeof e!=`function`,s=(e,t)=>Array.isArray(e)?e.map(e=>s(e,t)):a(e)?Object.keys(e).reduce((n,r)=>{let i=t(r),a=e[r];return n[i]=s(a,t),n},{}):e,c=(e,t,n)=>{let{filter:r}=n??{};if(Array.isArray(e)){let i=e.map((e,r)=>a(e)?c(e,t,n):t(e,r));return r?i.filter((e,t)=>r(e,t)):i}return a(e)?Object.keys(e).reduce((i,o)=>{let s=e[o],l;return l=a(s)||Array.isArray(s)?c(s,t,n):t(s,o),(!r||r(l,o))&&(i[o]=l),i},{}):e},l=(e,t)=>{let n={...e};for(let e of Object.keys(t)){let r=n[e],i=t[e];if(o(r)&&o(i)){n[e]=i;continue}if(Array.isArray(r)&&Array.isArray(i)){n[e]=r.concat(i);continue}if(a(r)&&a(i)){n[e]=l(r,i);continue}n[e]=i}return n},u=(e=``,t={})=>{let n=async(n,r={})=>{let o=new URL(e?`${e}${n}`:n),{params:s,parser:c,...u}=l(t,r);a(s)&&Object.entries(s).forEach(([e,t])=>{i(t)||o.searchParams.append(e,t.toString())}),(a(u.body)||Array.isArray(u.body))&&(u.body=JSON.stringify(u.body),u.headers={...u.headers,"Content-Type":`application/json`});let d=await fetch(o,u);if(!d.ok)throw d.headers.get(`Content-Type`)?.startsWith(`application/json`)?await d.json():Error(d.statusText);return await(c?.(d)??d.json())};return{get:(e,t)=>n(e,{...t,method:`GET`}),post:(e,t,r)=>n(e,{...r,method:`POST`,body:t}),put:(e,t,r)=>n(e,{...r,method:`PUT`,body:t}),delete:(e,t)=>n(e,{...t,method:`DELETE`})}},d=async e=>{try{return[null,await e]}catch(e){return[e,void 0]}},f=async e=>{let[t,n]=await d(fetch(e,{method:`HEAD`,redirect:`manual`}));return t?e:n.headers.get(`location`)||e},p=e=>{let t=new Uint8Array(e),n=``;for(let e=0;e<t.byteLength;e++)n+=String.fromCharCode(t[e]);return btoa(n)},m=async()=>{try{let e=await Function(`modulePath`,`return import(modulePath)`)(`sharp`);return e.default||e}catch{return null}},h=async(e,t,n,r)=>{let i=e(Buffer.from(t));if(n===`image/jpeg`)i=i.jpeg({quality:Math.round(r*100)});else if(n===`image/png`){let e=Math.round((1-r)*9);i=i.png({compressionLevel:e})}return`data:${n};base64,${(await i.toBuffer()).toString(`base64`)}`},g=async(e,t={})=>{let{quality:n=.92,compressor:r,fetcher:i=fetch}=t;if(!e.startsWith(`http`))throw Error(`图片地址必须以http或https开头`);let a=await i(e);if(!a.ok)throw Error(`获取图片失败: ${a.statusText}`);let o=a.headers.get(`Content-Type`)||`image/jpeg`,s=await a.arrayBuffer();if(o!==`image/jpeg`&&o!==`image/png`)return`data:${o};base64,${p(s)}`;if(r)return await r(s,o,n);if(typeof OffscreenCanvas<`u`){let e=null;try{let t=new Blob([s],{type:o});e=await createImageBitmap(t);let r=new OffscreenCanvas(e.width,e.height),i=r.getContext(`2d`);if(!i)throw Error(`无法获取 OffscreenCanvas context`);return i.drawImage(e,0,0),e.close(),e=null,`data:${o};base64,${p(await(await r.convertToBlob({type:o,quality:n})).arrayBuffer())}`}catch{return e?.close(),`data:${o};base64,${p(s)}`}}let c=await m();if(c)try{return await h(c,s,o,n)}catch{return`data:${o};base64,${p(s)}`}return`data:${o};base64,${p(s)}`},_=(e,t)=>Math.floor(Math.random()*(t-e+1))+e,v=e=>e.replace(/_([a-zA-Z])/g,(e,t)=>t.toUpperCase()),y=e=>e.replace(/([A-Z])/g,(e,t)=>`_${t.toLowerCase()}`),b=e=>e.charAt(0).toUpperCase()+e.slice(1),x=e=>e.charAt(0).toLowerCase()+e.slice(1),S=(e=``,t)=>{if(!e)return``;let{maxLength:n=1/0,disableNewLineReplace:r=!1,disableWhitespaceCollapse:i=!1,omission:a=`...`}=t??{},o=e;return o=r?o.replace(/\r?\n/g,` `):o.replace(/\r?\n/g,`\\n`),i||(o=o.replace(/\s+/g,` `)),o=o.trim(),n>0&&o.length>n?o.slice(0,n)+a:o},C={parse:e=>{let t=new URLSearchParams(e),n={};for(let[e,r]of t)Number.isNaN(Number(r))?n[e]=r:n[e]=Number(r);return n},stringify:(e,t)=>{let{addQueryPrefix:n=!1}=t??{},r=new URLSearchParams(e).toString();return r?n?`?${r}`:r:``}},w=(e,t=300)=>{let n=null;return(...r)=>{n&&clearTimeout(n),n=setTimeout(()=>{e(...r)},t)}},T=async(e=150)=>new Promise(t=>{setTimeout(t,e)}),E=(e,t=300)=>{let n=null;return function(...r){n||=setTimeout(()=>{n=null,e.apply(this,r)},t)}};export{y as camelToSnake,b as capitalize,S as compactStr,w as debounce,x as decapitalize,u as fetcher,f as getRealURL,g as imageUrlToBase64,r as isFalsy,i as isNil,a as isObject,o as isPrimitive,e as log,t as loopUntil,s as mapKeys,c as mapValues,l as mergeObjects,C as qs,_ as randomInt,T as sleep,v as snakeToCamel,E as throttle,d as to,n as withCache};
|
package/package.json
CHANGED
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nickyzj2023/utils",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"repository": {
|
|
5
|
-
"type": "git",
|
|
6
|
-
"url": "https://github.com/Nickyzj628/utils.git"
|
|
7
|
-
},
|
|
3
|
+
"version": "1.0.58",
|
|
8
4
|
"type": "module",
|
|
9
|
-
"main": "dist/index.
|
|
10
|
-
"module": "dist/index.
|
|
11
|
-
"types": "dist/index.d.
|
|
5
|
+
"main": "dist/index.mjs",
|
|
6
|
+
"module": "dist/index.mjs",
|
|
7
|
+
"types": "dist/index.d.mts",
|
|
12
8
|
"exports": {
|
|
13
9
|
".": {
|
|
14
|
-
"types": "./dist/index.d.
|
|
15
|
-
"import": "./dist/index.
|
|
10
|
+
"types": "./dist/index.d.mts",
|
|
11
|
+
"import": "./dist/index.mjs"
|
|
16
12
|
}
|
|
17
13
|
},
|
|
18
14
|
"files": [
|
|
19
15
|
"dist"
|
|
20
16
|
],
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "https://github.com/Nickyzj628/utils.git"
|
|
20
|
+
},
|
|
21
21
|
"devDependencies": {
|
|
22
22
|
"@biomejs/biome": "^2.4.4",
|
|
23
|
-
"@types/node": "^25.
|
|
24
|
-
"
|
|
23
|
+
"@types/node": "^25.5.0",
|
|
24
|
+
"tsdown": "^0.21.2",
|
|
25
25
|
"typedoc": "^0.28.17",
|
|
26
26
|
"typedoc-material-theme": "^1.4.1"
|
|
27
27
|
},
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"typescript": "^5.9.3"
|
|
30
30
|
},
|
|
31
31
|
"scripts": {
|
|
32
|
-
"
|
|
33
|
-
"
|
|
32
|
+
"build": "tsdown",
|
|
33
|
+
"docs": "typedoc src/index.ts --plugin typedoc-material-theme"
|
|
34
34
|
}
|
|
35
|
-
}
|
|
35
|
+
}
|
package/dist/index.js
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
var P=(e,s)=>{let{time:t=!0,fileName:n=!0}=s??{},a=[];if(t&&a.push(`[${new Date().toLocaleTimeString()}]`),n){let{stack:r}=new Error,i=r?.split(`
|
|
2
|
-
`)[2]?.trim()?.match(/at\s+(.*):(\d+)/);if(i?.[1]){let p=i[1].split(/[/\\]/).pop();a.push(`[${p}:${i[2]}]`)}}Array.isArray(e)?a.push(...e):a.push(e),console.log(...a)};var v=async(e,s)=>{let{maxRetries:t=5,shouldStop:n}=s??{},a;for(let r=0;r<t;r++)if(a=await e(r),n?.(a)===!0)return a;if(!n)return a;throw new Error(`\u8D85\u8FC7\u4E86\u6700\u5927\u5FAA\u73AF\u6B21\u6570\uFF08${t}\uFF09\u4E14\u672A\u6EE1\u8DB3\u505C\u6B62\u6267\u884C\u6761\u4EF6`)};var L=(e,s=-1)=>{let t=new Map,n=(...a)=>{let r=JSON.stringify(a),o=Date.now(),i=t.get(r);if(i&&o<i.expiresAt)return i.value;let p=s===-1?1/0:o+s*1e3,f={setTtl:u=>{p=o+u*1e3}},c=e.apply(f,a);if(c instanceof Promise){let u=c.then(m=>(t.set(r,{value:m,expiresAt:p}),m));return t.set(r,{value:u,expiresAt:p}),u}return t.set(r,{value:c,expiresAt:p}),c};return n.clear=()=>t.clear(),n.updateTtl=a=>{s=a;let r=Date.now(),o=r+a*1e3;for(let[i,p]of t.entries())p.expiresAt>r&&(p.expiresAt=o,t.set(i,p))},n};var q=e=>!e;var g=e=>e==null;var l=e=>e?.constructor===Object;var d=e=>e==null||typeof e!="object"&&typeof e!="function";var h=(e,s)=>Array.isArray(e)?e.map(t=>h(t,s)):l(e)?Object.keys(e).reduce((n,a)=>{let r=s(a),o=e[a];return n[r]=h(o,s),n},{}):e;var b=(e,s,t)=>{let{filter:n}=t??{};if(Array.isArray(e)){let a=e.map((r,o)=>l(r)?b(r,s,t):s(r,o));return n?a.filter((r,o)=>n(r,o)):a}return l(e)?Object.keys(e).reduce((r,o)=>{let i=e[o],p;return l(i)||Array.isArray(i)?p=b(i,s,t):p=s(i,o),(!n||n(p,o))&&(r[o]=p),r},{}):e};var x=(e,s)=>{let t={...e};for(let n of Object.keys(s)){let a=t[n],r=s[n];if(d(a)&&d(r)){t[n]=r;continue}if(Array.isArray(a)&&Array.isArray(r)){t[n]=a.concat(r);continue}if(l(a)&&l(r)){t[n]=x(a,r);continue}t[n]=r}return t};var ce=(e="",s={})=>{let t=async(n,a={})=>{let r=new URL(e?`${e}${n}`:n),{params:o,parser:i,...p}=x(s,a);l(o)&&Object.entries(o).forEach(([u,m])=>{g(m)||r.searchParams.append(u,m.toString())}),(l(p.body)||Array.isArray(p.body))&&(p.body=JSON.stringify(p.body),p.headers={...p.headers,"Content-Type":"application/json"});let f=await fetch(r,p);if(!f.ok)throw f.headers.get("Content-Type")?.startsWith("application/json")?await f.json():new Error(f.statusText);return await(i?.(f)??f.json())};return{get:(n,a)=>t(n,{...a,method:"GET"}),post:(n,a,r)=>t(n,{...r,method:"POST",body:a}),put:(n,a,r)=>t(n,{...r,method:"PUT",body:a}),delete:(n,a)=>t(n,{...a,method:"DELETE"})}};var w=async e=>{try{return[null,await e]}catch(s){return[s,void 0]}};var me=async e=>{let[s,t]=await w(fetch(e,{method:"HEAD",redirect:"manual"}));return s?e:t.headers.get("location")||e};var y=e=>{let s=new Uint8Array(e),t="";for(let n=0;n<s.byteLength;n++)t+=String.fromCharCode(s[n]);return btoa(t)},A=async()=>{try{let s=await new Function("modulePath","return import(modulePath)")("sharp");return s.default||s}catch{return null}},$=async(e,s,t,n)=>{let a=Buffer.from(s),r=e(a);if(t==="image/jpeg")r=r.jpeg({quality:Math.round(n*100)});else if(t==="image/png"){let i=Math.round((1-n)*9);r=r.png({compressionLevel:i})}let o=await r.toBuffer();return`data:${t};base64,${o.toString("base64")}`},de=async(e,s={})=>{let{quality:t=.92,compressor:n,fetcher:a=fetch}=s;if(!e.startsWith("http"))throw new Error("\u56FE\u7247\u5730\u5740\u5FC5\u987B\u4EE5http\u6216https\u5F00\u5934");let r=await a(e);if(!r.ok)throw new Error(`\u83B7\u53D6\u56FE\u7247\u5931\u8D25: ${r.statusText}`);let o=r.headers.get("Content-Type")||"image/jpeg",i=await r.arrayBuffer();if(o!=="image/jpeg"&&o!=="image/png"){let c=y(i);return`data:${o};base64,${c}`}if(n)return await n(i,o,t);if(typeof OffscreenCanvas<"u"){let c=null;try{let u=new Blob([i],{type:o});c=await createImageBitmap(u);let m=new OffscreenCanvas(c.width,c.height),T=m.getContext("2d");if(!T)throw new Error("\u65E0\u6CD5\u83B7\u53D6 OffscreenCanvas context");T.drawImage(c,0,0),c.close(),c=null;let S=await(await m.convertToBlob({type:o,quality:t})).arrayBuffer(),R=y(S);return`data:${o};base64,${R}`}catch{c?.close();let u=y(i);return`data:${o};base64,${u}`}}let p=await A();if(p)try{return await $(p,i,o,t)}catch{let c=y(i);return`data:${o};base64,${c}`}let f=y(i);return`data:${o};base64,${f}`};var Se=(e,s)=>Math.floor(Math.random()*(s-e+1))+e;var Ce=e=>e.replace(/_([a-zA-Z])/g,(s,t)=>t.toUpperCase()),Pe=e=>e.replace(/([A-Z])/g,(s,t)=>`_${t.toLowerCase()}`),Oe=e=>e.charAt(0).toUpperCase()+e.slice(1),ke=e=>e.charAt(0).toLowerCase()+e.slice(1);var ve=(e="",s)=>{if(!e)return"";let{maxLength:t=1/0,disableNewLineReplace:n=!1,disableWhitespaceCollapse:a=!1,omission:r="..."}=s??{},o=e;return n?o=o.replace(/\r?\n/g," "):o=o.replace(/\r?\n/g,"\\n"),a||(o=o.replace(/\s+/g," ")),o=o.trim(),t>0&&o.length>t?o.slice(0,t)+r:o};var Me=(e,s=300)=>{let t=null;return(...n)=>{t&&clearTimeout(t),t=setTimeout(()=>{e(...n)},s)}};var je=async(e=150)=>new Promise(s=>{setTimeout(s,e)});var Fe=(e,s=300)=>{let t=null;return function(...n){t||(t=setTimeout(()=>{t=null,e.apply(this,n)},s))}};export{Pe as camelToSnake,Oe as capitalize,ve as compactStr,Me as debounce,ke as decapitalize,ce as fetcher,me as getRealURL,de as imageUrlToBase64,q as isFalsy,g as isNil,l as isObject,d as isPrimitive,P as log,v as loopUntil,h as mapKeys,b as mapValues,x as mergeObjects,Se as randomInt,je as sleep,Ce as snakeToCamel,Fe as throttle,w as to,L as withCache};
|