pen-it 1.0.5 → 1.0.6

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/README.md CHANGED
@@ -418,6 +418,45 @@ import { isArray, formatFull, deepClone, unique } from 'pen-it'
418
418
  toArray(document.querySelectorAll('div'))
419
419
  ```
420
420
 
421
+ - **`mergeArrays(...arrays)`** — 合并多个数组。
422
+
423
+ ```ts
424
+ mergeArrays([1, 2], [3, 4], [5]) // [1, 2, 3, 4, 5]
425
+ ```
426
+
427
+ - **`flatten(arr, depth?)`** — 多维数组扁平化到指定层级(默认 1 层,传 `Infinity` 完全展开)。
428
+
429
+ ```ts
430
+ flatten([1, [2, [3, 4]], 5]) // [1, 2, [3, 4], 5]
431
+ flatten([1, [2, [3, 4]], 5], Infinity) // [1, 2, 3, 4, 5]
432
+ ```
433
+
434
+ - **`arrFind(arr, key, value)`** — 对象数组中按 key-value 查找第一个匹配项。
435
+
436
+ ```ts
437
+ arrFind([{ id: 1 }, { id: 2 }], 'id', 2) // { id: 2 }
438
+ ```
439
+
440
+ - **`groupBy(arr, key)`** — 对象数组按指定属性分组。
441
+
442
+ ```ts
443
+ groupBy([{ type: 'fruit' }, { type: 'vegetable' }], 'type')
444
+ // => { fruit: [...], vegetable: [...] }
445
+ ```
446
+
447
+ - **`filterEmptyValues(obj)`** — 移除对象中值为空(null / undefined / 空字符串)的属性。
448
+
449
+ ```ts
450
+ filterEmptyValues({ a: 1, b: '', c: null }) // { a: 1 }
451
+ ```
452
+
453
+ - **`createRange(length, mapFn?)`** — 快速生成范围数组。
454
+
455
+ ```ts
456
+ createRange(5) // [0, 1, 2, 3, 4]
457
+ createRange(3, (i) => i * 2) // [0, 2, 4]
458
+ ```
459
+
421
460
  ---
422
461
 
423
462
  ### Cookie — `cookie`
@@ -504,6 +543,17 @@ import { isArray, formatFull, deepClone, unique } from 'pen-it'
504
543
  const off = onScroll(y => console.log(y))
505
544
  ```
506
545
 
546
+ #### 可视区域检测
547
+
548
+ - **`observeIntersection(target, onEnter, onLeave?, options?)`** — 监听元素进入/离开可视区域,返回清理函数。
549
+
550
+ ```ts
551
+ const cleanup = observeIntersection(
552
+ document.querySelector('.footer')!,
553
+ () => loadMore(10),
554
+ );
555
+ ```
556
+
507
557
  ---
508
558
 
509
559
  ### 防抖与节流 — `control`
@@ -55,3 +55,65 @@ export declare const sortByKey: <T extends Record<string, any>>(arr: T[], key: k
55
55
  * // => [div, div, ...]
56
56
  */
57
57
  export declare const toArray: <T>(arrayLike: ArrayLike<T>) => T[];
58
+ /**
59
+ * 合并多个数组
60
+ * @param arrays - 一个或多个数组
61
+ * @returns 合并后的新数组
62
+ * @example
63
+ * mergeArrays([1, 2], [3, 4], [5])
64
+ * // => [1, 2, 3, 4, 5]
65
+ */
66
+ export declare const mergeArrays: <T>(...arrays: T[][]) => T[];
67
+ /**
68
+ * 将多维数组扁平化到指定层级
69
+ * @param arr - 多维数组
70
+ * @param depth - 扁平化深度,默认 1(仅展开一层)。传 Infinity 可完全扁平化为一维
71
+ * @returns 扁平化后的数组
72
+ * @example
73
+ * flatten([1, [2, [3, 4]], 5])
74
+ * // => [1, 2, [3, 4], 5]
75
+ * @example
76
+ * flatten([1, [2, [3, 4]], 5], Infinity)
77
+ * // => [1, 2, 3, 4, 5]
78
+ */
79
+ export declare const flatten: <T>(arr: any[], depth?: number) => T[];
80
+ /**
81
+ * 在对象数组中按 key-value 查找第一个匹配项
82
+ * @param arr - 对象数组
83
+ * @param key - 要匹配的键名
84
+ * @param value - 要匹配的键值
85
+ * @returns 第一个匹配的对象,无匹配则返回 undefined
86
+ * @example
87
+ * arrFind([{ id: 1, name: "a" }, { id: 2, name: "b" }], "id", 2)
88
+ * // => { id: 2, name: "b" }
89
+ */
90
+ export declare const arrFind: <T extends Record<string, any>>(arr: T[], key: keyof T, value: T[keyof T]) => T | undefined;
91
+ /**
92
+ * 将对象数组按指定属性分组
93
+ * @param arr - 对象数组
94
+ * @param key - 用于分组的属性名
95
+ * @returns 以属性值为键、对应数组为值的对象
96
+ * @example
97
+ * groupBy([{ type: "fruit", name: "apple" }, { type: "vegetable", name: "carrot" }], "type")
98
+ * // => { fruit: [{ type: "fruit", name: "apple" }], vegetable: [{ type: "vegetable", name: "carrot" }] }
99
+ */
100
+ export declare const groupBy: <T extends Record<string, any>>(arr: T[], key: keyof T) => Record<string, T[]>;
101
+ /**
102
+ * 移除对象中值为空(null / undefined / 空字符串)的属性
103
+ * @param obj - 待过滤的对象
104
+ * @returns 过滤后的新对象
105
+ * @example
106
+ * filterEmptyValues({ a: 1, b: "", c: null, d: 3 })
107
+ * // => { a: 1, d: 3 }
108
+ */
109
+ export declare const filterEmptyValues: <T extends Record<string, any>>(obj: T) => Partial<T>;
110
+ /**
111
+ * 根据长度和映射函数快速生成数组
112
+ * @param length - 数组长度
113
+ * @param mapFn - 映射函数,接收索引返回元素值,默认为返回索引
114
+ * @returns 生成的数组
115
+ * @example
116
+ * createRange(5)
117
+ * // => [0, 1, 2, 3, 4]
118
+ */
119
+ export declare const createRange: <T = number>(length: number, mapFn?: (index: number) => T) => T[];
@@ -76,3 +76,18 @@ export declare const scrollToBottom: (behavior?: ScrollBehavior) => void;
76
76
  * cleanup(); // 停止监听
77
77
  */
78
78
  export declare const onScroll: (callback: (scrollY: number) => void) => () => void;
79
+ /**
80
+ * 监听目标元素是否进入/离开可视区域
81
+ * @param target - 目标 DOM 元素
82
+ * @param onEnter - 元素进入可视区域时的回调
83
+ * @param onLeave - 元素离开可视区域时的回调(可选)
84
+ * @param options - IntersectionObserver 配置项
85
+ * @returns 清理函数,调用后停止观察
86
+ * @example
87
+ * const cleanup = observeIntersection(
88
+ * document.querySelector(".footer")!,
89
+ * () => loadMore(10),
90
+ * );
91
+ * cleanup(); // 停止观察
92
+ */
93
+ export declare const observeIntersection: (target: Element, onEnter: (entry: IntersectionObserverEntry) => void, onLeave?: (entry: IntersectionObserverEntry) => void, options?: IntersectionObserverInit) => () => void;
package/dist/index.cjs CHANGED
@@ -844,6 +844,85 @@ const sortByKey = (arr, key, order = "asc") => {
844
844
  const toArray = (arrayLike) => {
845
845
  return Array.from(arrayLike);
846
846
  };
847
+ /**
848
+ * 合并多个数组
849
+ * @param arrays - 一个或多个数组
850
+ * @returns 合并后的新数组
851
+ * @example
852
+ * mergeArrays([1, 2], [3, 4], [5])
853
+ * // => [1, 2, 3, 4, 5]
854
+ */
855
+ const mergeArrays = (...arrays) => {
856
+ return [].concat(...arrays);
857
+ };
858
+ /**
859
+ * 将多维数组扁平化到指定层级
860
+ * @param arr - 多维数组
861
+ * @param depth - 扁平化深度,默认 1(仅展开一层)。传 Infinity 可完全扁平化为一维
862
+ * @returns 扁平化后的数组
863
+ * @example
864
+ * flatten([1, [2, [3, 4]], 5])
865
+ * // => [1, 2, [3, 4], 5]
866
+ * @example
867
+ * flatten([1, [2, [3, 4]], 5], Infinity)
868
+ * // => [1, 2, 3, 4, 5]
869
+ */
870
+ const flatten = (arr, depth = 1) => {
871
+ return arr.flat(depth);
872
+ };
873
+ /**
874
+ * 在对象数组中按 key-value 查找第一个匹配项
875
+ * @param arr - 对象数组
876
+ * @param key - 要匹配的键名
877
+ * @param value - 要匹配的键值
878
+ * @returns 第一个匹配的对象,无匹配则返回 undefined
879
+ * @example
880
+ * arrFind([{ id: 1, name: "a" }, { id: 2, name: "b" }], "id", 2)
881
+ * // => { id: 2, name: "b" }
882
+ */
883
+ const arrFind = (arr, key, value) => {
884
+ return arr.find((item) => item[key] === value);
885
+ };
886
+ /**
887
+ * 将对象数组按指定属性分组
888
+ * @param arr - 对象数组
889
+ * @param key - 用于分组的属性名
890
+ * @returns 以属性值为键、对应数组为值的对象
891
+ * @example
892
+ * groupBy([{ type: "fruit", name: "apple" }, { type: "vegetable", name: "carrot" }], "type")
893
+ * // => { fruit: [{ type: "fruit", name: "apple" }], vegetable: [{ type: "vegetable", name: "carrot" }] }
894
+ */
895
+ const groupBy = (arr, key) => {
896
+ return arr.reduce((acc, item) => {
897
+ const groupKey = String(item[key]);
898
+ if (!acc[groupKey]) acc[groupKey] = [];
899
+ acc[groupKey].push(item);
900
+ return acc;
901
+ }, {});
902
+ };
903
+ /**
904
+ * 移除对象中值为空(null / undefined / 空字符串)的属性
905
+ * @param obj - 待过滤的对象
906
+ * @returns 过滤后的新对象
907
+ * @example
908
+ * filterEmptyValues({ a: 1, b: "", c: null, d: 3 })
909
+ * // => { a: 1, d: 3 }
910
+ */
911
+ const filterEmptyValues = (obj) => {
912
+ return Object.fromEntries(Object.entries(obj).filter(([, v]) => v !== null && v !== void 0 && v !== ""));
913
+ };
914
+ /**
915
+ * 根据长度和映射函数快速生成数组
916
+ * @param length - 数组长度
917
+ * @param mapFn - 映射函数,接收索引返回元素值,默认为返回索引
918
+ * @returns 生成的数组
919
+ * @example
920
+ * createRange(5)
921
+ * // => [0, 1, 2, 3, 4]
922
+ */
923
+ const createRange = (length, mapFn) => {
924
+ return Array.from({ length }, (_, i) => mapFn ? mapFn(i) : i);
925
+ };
847
926
  //#endregion
848
927
  //#region src/cookie/index.ts
849
928
  /**
@@ -1019,6 +1098,30 @@ const onScroll = (callback) => {
1019
1098
  window.addEventListener("scroll", handler);
1020
1099
  return () => window.removeEventListener("scroll", handler);
1021
1100
  };
1101
+ /**
1102
+ * 监听目标元素是否进入/离开可视区域
1103
+ * @param target - 目标 DOM 元素
1104
+ * @param onEnter - 元素进入可视区域时的回调
1105
+ * @param onLeave - 元素离开可视区域时的回调(可选)
1106
+ * @param options - IntersectionObserver 配置项
1107
+ * @returns 清理函数,调用后停止观察
1108
+ * @example
1109
+ * const cleanup = observeIntersection(
1110
+ * document.querySelector(".footer")!,
1111
+ * () => loadMore(10),
1112
+ * );
1113
+ * cleanup(); // 停止观察
1114
+ */
1115
+ const observeIntersection = (target, onEnter, onLeave, options) => {
1116
+ const observer = new IntersectionObserver((entries) => {
1117
+ entries.forEach((entry) => {
1118
+ if (entry.isIntersecting) onEnter(entry);
1119
+ else if (onLeave) onLeave(entry);
1120
+ });
1121
+ }, options);
1122
+ observer.observe(target);
1123
+ return () => observer.disconnect();
1124
+ };
1022
1125
  //#endregion
1023
1126
  //#region src/control/index.ts
1024
1127
  /**
@@ -1106,19 +1209,23 @@ const throttle = (fn, interval = 300, { leading = true, trailing = true } = {})
1106
1209
  return throttled;
1107
1210
  };
1108
1211
  //#endregion
1212
+ exports.arrFind = arrFind;
1109
1213
  exports.camelToKebab = camelToKebab;
1110
1214
  exports.capitalize = capitalize;
1111
1215
  exports.compactCN = compactCN;
1112
1216
  exports.compactEN = compactEN;
1113
1217
  exports.copyToClipboard = copyToClipboard;
1218
+ exports.createRange = createRange;
1114
1219
  exports.debounce = debounce;
1115
1220
  exports.deepClone = deepClone;
1116
1221
  exports.deepCloneWithJSON = deepCloneWithJSON;
1117
1222
  exports.delCookie = delCookie;
1118
1223
  exports.downloadFile = downloadFile;
1119
1224
  exports.exportJSON = exportJSON;
1225
+ exports.filterEmptyValues = filterEmptyValues;
1120
1226
  exports.firstLower = firstLower;
1121
1227
  exports.firstUpper = firstUpper;
1228
+ exports.flatten = flatten;
1122
1229
  exports.formatFull = formatFull;
1123
1230
  exports.formatFullReplace = formatFullReplace;
1124
1231
  exports.formatNum = formatNum;
@@ -1128,6 +1235,7 @@ exports.formatYMD = formatYMD;
1128
1235
  exports.getCookie = getCookie;
1129
1236
  exports.getUrlParam = getUrlParam;
1130
1237
  exports.getUrlParams = getUrlParams;
1238
+ exports.groupBy = groupBy;
1131
1239
  exports.is = is;
1132
1240
  exports.isArray = isArray;
1133
1241
  exports.isAsyncFunction = isAsyncFunction;
@@ -1161,6 +1269,8 @@ exports.localGet = localGet;
1161
1269
  exports.localRm = localRm;
1162
1270
  exports.localSet = localSet;
1163
1271
  exports.maskPhone = maskPhone;
1272
+ exports.mergeArrays = mergeArrays;
1273
+ exports.observeIntersection = observeIntersection;
1164
1274
  exports.onScroll = onScroll;
1165
1275
  exports.percentCN = percentCN;
1166
1276
  exports.reverse = reverse;
package/dist/index.js CHANGED
@@ -843,6 +843,85 @@ const sortByKey = (arr, key, order = "asc") => {
843
843
  const toArray = (arrayLike) => {
844
844
  return Array.from(arrayLike);
845
845
  };
846
+ /**
847
+ * 合并多个数组
848
+ * @param arrays - 一个或多个数组
849
+ * @returns 合并后的新数组
850
+ * @example
851
+ * mergeArrays([1, 2], [3, 4], [5])
852
+ * // => [1, 2, 3, 4, 5]
853
+ */
854
+ const mergeArrays = (...arrays) => {
855
+ return [].concat(...arrays);
856
+ };
857
+ /**
858
+ * 将多维数组扁平化到指定层级
859
+ * @param arr - 多维数组
860
+ * @param depth - 扁平化深度,默认 1(仅展开一层)。传 Infinity 可完全扁平化为一维
861
+ * @returns 扁平化后的数组
862
+ * @example
863
+ * flatten([1, [2, [3, 4]], 5])
864
+ * // => [1, 2, [3, 4], 5]
865
+ * @example
866
+ * flatten([1, [2, [3, 4]], 5], Infinity)
867
+ * // => [1, 2, 3, 4, 5]
868
+ */
869
+ const flatten = (arr, depth = 1) => {
870
+ return arr.flat(depth);
871
+ };
872
+ /**
873
+ * 在对象数组中按 key-value 查找第一个匹配项
874
+ * @param arr - 对象数组
875
+ * @param key - 要匹配的键名
876
+ * @param value - 要匹配的键值
877
+ * @returns 第一个匹配的对象,无匹配则返回 undefined
878
+ * @example
879
+ * arrFind([{ id: 1, name: "a" }, { id: 2, name: "b" }], "id", 2)
880
+ * // => { id: 2, name: "b" }
881
+ */
882
+ const arrFind = (arr, key, value) => {
883
+ return arr.find((item) => item[key] === value);
884
+ };
885
+ /**
886
+ * 将对象数组按指定属性分组
887
+ * @param arr - 对象数组
888
+ * @param key - 用于分组的属性名
889
+ * @returns 以属性值为键、对应数组为值的对象
890
+ * @example
891
+ * groupBy([{ type: "fruit", name: "apple" }, { type: "vegetable", name: "carrot" }], "type")
892
+ * // => { fruit: [{ type: "fruit", name: "apple" }], vegetable: [{ type: "vegetable", name: "carrot" }] }
893
+ */
894
+ const groupBy = (arr, key) => {
895
+ return arr.reduce((acc, item) => {
896
+ const groupKey = String(item[key]);
897
+ if (!acc[groupKey]) acc[groupKey] = [];
898
+ acc[groupKey].push(item);
899
+ return acc;
900
+ }, {});
901
+ };
902
+ /**
903
+ * 移除对象中值为空(null / undefined / 空字符串)的属性
904
+ * @param obj - 待过滤的对象
905
+ * @returns 过滤后的新对象
906
+ * @example
907
+ * filterEmptyValues({ a: 1, b: "", c: null, d: 3 })
908
+ * // => { a: 1, d: 3 }
909
+ */
910
+ const filterEmptyValues = (obj) => {
911
+ return Object.fromEntries(Object.entries(obj).filter(([, v]) => v !== null && v !== void 0 && v !== ""));
912
+ };
913
+ /**
914
+ * 根据长度和映射函数快速生成数组
915
+ * @param length - 数组长度
916
+ * @param mapFn - 映射函数,接收索引返回元素值,默认为返回索引
917
+ * @returns 生成的数组
918
+ * @example
919
+ * createRange(5)
920
+ * // => [0, 1, 2, 3, 4]
921
+ */
922
+ const createRange = (length, mapFn) => {
923
+ return Array.from({ length }, (_, i) => mapFn ? mapFn(i) : i);
924
+ };
846
925
  //#endregion
847
926
  //#region src/cookie/index.ts
848
927
  /**
@@ -1018,6 +1097,30 @@ const onScroll = (callback) => {
1018
1097
  window.addEventListener("scroll", handler);
1019
1098
  return () => window.removeEventListener("scroll", handler);
1020
1099
  };
1100
+ /**
1101
+ * 监听目标元素是否进入/离开可视区域
1102
+ * @param target - 目标 DOM 元素
1103
+ * @param onEnter - 元素进入可视区域时的回调
1104
+ * @param onLeave - 元素离开可视区域时的回调(可选)
1105
+ * @param options - IntersectionObserver 配置项
1106
+ * @returns 清理函数,调用后停止观察
1107
+ * @example
1108
+ * const cleanup = observeIntersection(
1109
+ * document.querySelector(".footer")!,
1110
+ * () => loadMore(10),
1111
+ * );
1112
+ * cleanup(); // 停止观察
1113
+ */
1114
+ const observeIntersection = (target, onEnter, onLeave, options) => {
1115
+ const observer = new IntersectionObserver((entries) => {
1116
+ entries.forEach((entry) => {
1117
+ if (entry.isIntersecting) onEnter(entry);
1118
+ else if (onLeave) onLeave(entry);
1119
+ });
1120
+ }, options);
1121
+ observer.observe(target);
1122
+ return () => observer.disconnect();
1123
+ };
1021
1124
  //#endregion
1022
1125
  //#region src/control/index.ts
1023
1126
  /**
@@ -1105,4 +1208,4 @@ const throttle = (fn, interval = 300, { leading = true, trailing = true } = {})
1105
1208
  return throttled;
1106
1209
  };
1107
1210
  //#endregion
1108
- export { camelToKebab, capitalize, compactCN, compactEN, copyToClipboard, debounce, deepClone, deepCloneWithJSON, delCookie, downloadFile, exportJSON, firstLower, firstUpper, formatFull, formatFullReplace, formatNum, formatRmb, formatWeek, formatYMD, getCookie, getUrlParam, getUrlParams, is, isArray, isAsyncFunction, isBoolean, isDate, isDef, isElement, isEmpty, isEmptySv, isEqual, isFloat, isFunction, isHexColor, isIOS, isInt, isNull, isNullOrUnDef, isNumber, isObject, isPC, isPrimitive, isPromise, isString, isSymbol, isUnDef, isValidEmail, isWindow, kebabToCamel, localClear, localGet, localRm, localSet, maskPhone, onScroll, percentCN, reverse, scrollToBottom, scrollToTop, setCookie, shallowClone, signed, sortByKey, sortNumAsc, sortNumDesc, spacePhone, throttle, toArray, toCamel, toQueryString, trimAll, truncate, truncateByWords, unique, uniqueByKey };
1211
+ export { arrFind, camelToKebab, capitalize, compactCN, compactEN, copyToClipboard, createRange, debounce, deepClone, deepCloneWithJSON, delCookie, downloadFile, exportJSON, filterEmptyValues, firstLower, firstUpper, flatten, formatFull, formatFullReplace, formatNum, formatRmb, formatWeek, formatYMD, getCookie, getUrlParam, getUrlParams, groupBy, is, isArray, isAsyncFunction, isBoolean, isDate, isDef, isElement, isEmpty, isEmptySv, isEqual, isFloat, isFunction, isHexColor, isIOS, isInt, isNull, isNullOrUnDef, isNumber, isObject, isPC, isPrimitive, isPromise, isString, isSymbol, isUnDef, isValidEmail, isWindow, kebabToCamel, localClear, localGet, localRm, localSet, maskPhone, mergeArrays, observeIntersection, onScroll, percentCN, reverse, scrollToBottom, scrollToTop, setCookie, shallowClone, signed, sortByKey, sortNumAsc, sortNumDesc, spacePhone, throttle, toArray, toCamel, toQueryString, trimAll, truncate, truncateByWords, unique, uniqueByKey };
package/package.json CHANGED
@@ -1,63 +1,63 @@
1
- {
2
- "name": "pen-it",
3
- "version": "1.0.5",
4
- "description": "用笔锚定记忆中的前端常用工具函数,一个轻量级的前端实用程序库,支持类型检查、日期/数字格式化、字符串操作、数据存储、深度克隆、数组操作、Cookie 以及浏览器 API",
5
- "type": "module",
6
- "main": "dist/index.cjs",
7
- "module": "dist/index.js",
8
- "types": "dist/index.d.ts",
9
- "exports": {
10
- ".": {
11
- "import": "./dist/index.js",
12
- "require": "./dist/index.cjs",
13
- "types": "./dist/index.d.ts"
14
- }
15
- },
16
- "scripts": {
17
- "build": "rimraf dist && rolldown -c rolldown.config.js",
18
- "test": "vitest"
19
- },
20
- "files": [
21
- "dist"
22
- ],
23
- "keywords": [
24
- "utils",
25
- "utilities",
26
- "toolkit",
27
- "helpers",
28
- "frontend",
29
- "typescript",
30
- "type-checking",
31
- "date-format",
32
- "number-format",
33
- "deep-clone",
34
- "string-manipulation",
35
- "array-operations",
36
- "cookie",
37
- "localstorage",
38
- "browser-api",
39
- "debounce",
40
- "throttle"
41
- ],
42
- "author": "newborn_calf",
43
- "license": "MIT",
44
- "repository": {
45
- "type": "git",
46
- "url": "https://github.com/Libao-Jun/pen-it"
47
- },
48
- "homepage": "https://github.com/Libao-Jun/pen-it#readme",
49
- "bugs": {
50
- "url": "https://github.com/Libao-Jun/pen-it/issues"
51
- },
52
- "packageManager": "pnpm@10.19.0",
53
- "devDependencies": {
54
- "@rollup/plugin-typescript": "^12.3.0",
55
- "@vitest/coverage-v8": "^4.1.8",
56
- "jsdom": "^29.1.1",
57
- "rimraf": "^6.1.3",
58
- "rolldown": "^1.0.3",
59
- "tslib": "^2.8.1",
60
- "typescript": "^6.0.3",
61
- "vitest": "^4.1.8"
62
- }
1
+ {
2
+ "name": "pen-it",
3
+ "version": "1.0.6",
4
+ "description": "用笔锚定记忆中的前端常用工具函数,一个轻量级的前端实用程序库,支持类型检查、日期/数字格式化、字符串操作、数据存储、深度克隆、数组操作、Cookie 以及浏览器 API",
5
+ "type": "module",
6
+ "main": "dist/index.cjs",
7
+ "module": "dist/index.js",
8
+ "types": "dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "import": "./dist/index.js",
12
+ "require": "./dist/index.cjs",
13
+ "types": "./dist/index.d.ts"
14
+ }
15
+ },
16
+ "scripts": {
17
+ "build": "rimraf dist && rolldown -c rolldown.config.js",
18
+ "test": "vitest"
19
+ },
20
+ "files": [
21
+ "dist"
22
+ ],
23
+ "keywords": [
24
+ "utils",
25
+ "utilities",
26
+ "toolkit",
27
+ "helpers",
28
+ "frontend",
29
+ "typescript",
30
+ "type-checking",
31
+ "date-format",
32
+ "number-format",
33
+ "deep-clone",
34
+ "string-manipulation",
35
+ "array-operations",
36
+ "cookie",
37
+ "localstorage",
38
+ "browser-api",
39
+ "debounce",
40
+ "throttle"
41
+ ],
42
+ "author": "newborn_calf",
43
+ "license": "MIT",
44
+ "repository": {
45
+ "type": "git",
46
+ "url": "https://github.com/Libao-Jun/pen-it"
47
+ },
48
+ "homepage": "https://github.com/Libao-Jun/pen-it#readme",
49
+ "bugs": {
50
+ "url": "https://github.com/Libao-Jun/pen-it/issues"
51
+ },
52
+ "packageManager": "pnpm@10.19.0",
53
+ "devDependencies": {
54
+ "@rollup/plugin-typescript": "^12.3.0",
55
+ "@vitest/coverage-v8": "^4.1.8",
56
+ "jsdom": "^29.1.1",
57
+ "rimraf": "^6.1.3",
58
+ "rolldown": "^1.0.3",
59
+ "tslib": "^2.8.1",
60
+ "typescript": "^6.0.3",
61
+ "vitest": "^4.1.8"
62
+ }
63
63
  }