@pmun/utils 0.2.4 → 0.3.1

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 CHANGED
@@ -272,6 +272,34 @@ type KeysMatching<T, V> = {
272
272
  * ```
273
273
  */
274
274
  declare function arrayToObject<T>(arr: T[], key: KeysMatching<T, string | number>): Record<string, T>;
275
+ /**
276
+ * 替换数组数据中指定字段的 `&nbsp;` 为不换行空格
277
+ *
278
+ * @param {Array<Record<string, any>>} arr - 数组
279
+ * @param {string} key - 需要处理的字段名
280
+ * @returns {Array<Record<string, any>>} 处理后的数据数组
281
+ *
282
+ * @group String
283
+ * @example
284
+ * ```ts
285
+ * // 基本用法
286
+ * const data = [
287
+ * { name: 'John&nbsp;Doe', age: 30 },
288
+ * { name: 'Jane&nbsp;&nbsp;Smith', age: 25 }
289
+ * ]
290
+ * const result = arrayReplaceNBSP(data, 'name')
291
+ * // 结果: [
292
+ * // { name: 'John Doe', age: 30 },
293
+ * // { name: 'Jane Smith', age: 25 }
294
+ * // ]
295
+ *
296
+ * // 空数组情况
297
+ * const emptyData = []
298
+ * const result = arrayReplaceNBSP(emptyData, 'name')
299
+ * // 结果: []
300
+ * ```
301
+ */
302
+ declare function arrayReplaceNBSP<T extends Record<string, string | number | boolean | object>>(arr: T[], key: string): T[];
275
303
 
276
304
  /**
277
305
  * 表示日期的各种类型,可以是日期对象、日期字符串或时间戳
@@ -1309,46 +1337,21 @@ declare function isEmptyString(str: string): boolean;
1309
1337
  */
1310
1338
  declare function ensureRpxUnit(val: string | number): string;
1311
1339
  /**
1312
- * 替换表格数据中指定字段的 &nbsp; 为不换行空格
1340
+ * 替换字符串中的 `&nbsp;` 为不换行空格
1313
1341
  *
1314
- * @param {Array<Record<string, any>>} tableData - 表格数据数组或Vue ref
1315
- * @param {string} key - 需要处理的字段名
1316
- * @returns {Array<Record<string, any>>} 处理后的表格数据数组
1342
+ * @param {string} str - 字符串
1343
+ * @returns {string} 处理后的字符串
1317
1344
  *
1318
1345
  * @group String
1319
1346
  * @example
1320
1347
  * ```ts
1321
1348
  * // 基本用法
1322
- * const data = [
1323
- * { name: 'John&nbsp;Doe', age: 30 },
1324
- * { name: 'Jane&nbsp;&nbsp;Smith', age: 25 }
1325
- * ]
1326
- * const result = replaceNBSP(data, 'name')
1327
- * // 结果: [
1328
- * // { name: 'John Doe', age: 30 },
1329
- * // { name: 'Jane Smith', age: 25 }
1330
- * // ]
1331
- *
1332
- * // 使用ref包装的数据 (在Vue中使用)
1333
- * const refData = ref([
1334
- * { desc: 'Product&nbsp;Info', price: 99 },
1335
- * { desc: 'Service&nbsp;&nbsp;Details', price: 50 }
1336
- * ])
1337
- * const result = replaceNBSP(refData, 'desc')
1338
- * // 结果: [
1339
- * // { desc: 'Product Info', price: 99 },
1340
- * // { desc: 'Service Details', price: 50 }
1341
- * // ]
1342
- *
1343
- * // 空数组情况
1344
- * const emptyData = []
1345
- * const result = replaceNBSP(emptyData, 'name')
1346
- * // 结果: []
1349
+ * replaceNBSP('John&nbsp;Doe') // 'John Doe'
1350
+ * replaceNBSP('Jane&nbsp;&nbsp;Smith') // 'Jane Smith'
1351
+ * replaceNBSP('Smith') // 'Smith'
1347
1352
  * ```
1348
1353
  */
1349
- declare function replaceNBSP<T extends Record<string, string | number | boolean | object>>(tableData: T[] | {
1350
- value: T[];
1351
- }, key: string): T[];
1354
+ declare function replaceNBSP(str?: string): string;
1352
1355
 
1353
1356
  /**
1354
1357
  * 将对象转换为URL查询字符串
@@ -1378,4 +1381,4 @@ declare function replaceNBSP<T extends Record<string, string | number | boolean
1378
1381
  */
1379
1382
  declare function getQueryStringify(params: Record<string, any> | null | undefined): string;
1380
1383
 
1381
- export { type DateLike, add, addDays, addMonths, addYears, appendUniversalOption, arrayToObject, camelToKebab, capitalize, chunk, clamp, convertToDayjsParam, createDate, deepClone, deepMerge, delay, diff, endOf, ensureRpxUnit, escapeHtml, filterObjectByKeys, first, formatCurrency, formatDate, formatFullTime, formatHumanReadable, formatNumberWithTenThousand, formatThousands, fromNow, get, getDayOfWeek, getDaysInMonth, getQueryStringify, groupBy, hasOwnProp, isArray, isBoolean, isDate, isDateInRange, isEmpty, isEmptyObject, isEmptyString, isEqual, isEven, isFunction, isMap, isMillisecondTimestamp, isNaN, isNull, isNullOrUndefined, isNumber, isObject, isOdd, isPlainObject, isPrimitive, isPromise, isRegExp, isSet, isString, isSymbol, isUndefined, isValidEmail, isValidUrl, kebabToCamel, last, merge, now, objectToQueryString, omit, parseDate, percentage, pick, randomInt, randomString, remove, renameTreeNodes, replaceNBSP, round, sample, shuffle, startOf, transformTree, truncate, unique };
1384
+ export { type DateLike, add, addDays, addMonths, addYears, appendUniversalOption, arrayReplaceNBSP, arrayToObject, camelToKebab, capitalize, chunk, clamp, convertToDayjsParam, createDate, deepClone, deepMerge, delay, diff, endOf, ensureRpxUnit, escapeHtml, filterObjectByKeys, first, formatCurrency, formatDate, formatFullTime, formatHumanReadable, formatNumberWithTenThousand, formatThousands, fromNow, get, getDayOfWeek, getDaysInMonth, getQueryStringify, groupBy, hasOwnProp, isArray, isBoolean, isDate, isDateInRange, isEmpty, isEmptyObject, isEmptyString, isEqual, isEven, isFunction, isMap, isMillisecondTimestamp, isNaN, isNull, isNullOrUndefined, isNumber, isObject, isOdd, isPlainObject, isPrimitive, isPromise, isRegExp, isSet, isString, isSymbol, isUndefined, isValidEmail, isValidUrl, kebabToCamel, last, merge, now, objectToQueryString, omit, parseDate, percentage, pick, randomInt, randomString, remove, renameTreeNodes, replaceNBSP, round, sample, shuffle, startOf, transformTree, truncate, unique };
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import i from'dayjs';import S from'dayjs/plugin/isBetween';import N from'dayjs/plugin/isSameOrAfter';import A from'dayjs/plugin/isSameOrBefore';import U from'dayjs/plugin/relativeTime';import'dayjs/locale/zh-cn';function b(n){return typeof n=="string"}function p(n){return typeof n=="number"&&!a(n)}function P(n){return typeof n=="boolean"}function x(n){return typeof n=="function"}function m(n){return n!==null&&typeof n=="object"}function h(n){return Array.isArray(n)}function $(n){return n instanceof Date}function H(n){return n instanceof RegExp}function Y(n){return m(n)&&x(n.then)&&x(n.catch)}function C(n){return n instanceof Map}function V(n){return n instanceof Set}function F(n){return typeof n=="symbol"}function I(n){return n===null||typeof n!="object"&&typeof n!="function"}function D(n){return typeof n>"u"}function k(n){return n===null}function w(n){return k(n)||D(n)}function R(n){return m(n)&&Object.keys(n).length===0}function B(n){return w(n)?true:b(n)?n.trim().length===0:h(n)?n.length===0:m(n)?R(n):false}function a(n){return Number.isNaN(n)}function f(n){if(typeof n!="object"||n===null)return false;let t=Object.getPrototypeOf(n);return t===Object.prototype||t===null}function d(n,t){return Object.prototype.hasOwnProperty.call(n,t)}function g(n){if(n===null||typeof n!="object")return n;if(n instanceof Date)return new Date(n.getTime());if(n instanceof RegExp)return new RegExp(n.source,n.flags);if(Array.isArray(n))return n.map(e=>g(e));let t={};return Object.keys(n).forEach(e=>{t[e]=g(n[e]);}),t}function q(n,t,e){let r=t.split("."),o=n;for(let u of r){if(o==null)return e;o=o[u];}return o===void 0?e:o}function v(n,t){return t.reduce((e,r)=>(r in n&&(e[r]=n[r]),e),{})}function Z(n,t){let e={...n};return t.forEach(r=>{delete e[r];}),e}function y(n){return Object.entries(n).filter(([t,e])=>e!=null).map(([t,e])=>Array.isArray(e)?e.map(r=>`${encodeURIComponent(t)}=${encodeURIComponent(String(r))}`).join("&"):`${encodeURIComponent(t)}=${encodeURIComponent(String(e))}`).join("&")}function W(...n){return Object.assign({},...n)}function M(...n){let t={};return n.forEach(e=>{f(e)&&Object.keys(e).forEach(r=>{let o=e[r],u=t[r];f(o)&&f(u)?t[r]=M(u,o):t[r]=g(o);});}),t}function _(n,t,e={}){return t.reduce((r,o)=>{if(d(n,o)){let u=e[o]||o;r[u]=n[o];}return r},{})}function X(n,t){return n.filter(e=>e!==t)}function nn(n){return Array.from(new Set(n))}function tn(n,t){if(t<=0)return [n];let e=[];for(let r=0;r<n.length;r+=t)e.push(n.slice(r,r+t));return e}function en(n){return n.length>0?n[n.length-1]:void 0}function rn(n){return n.length>0?n[0]:void 0}function on(n){let t=[...n];for(let e=t.length-1;e>0;e--){let r=Math.floor(Math.random()*(e+1));[t[e],t[r]]=[t[r],t[e]];}return t}function un(n){if(n.length===0)return;let t=Math.floor(Math.random()*n.length);return n[t]}function sn(n,t){return n.length!==t.length?false:n.every((e,r)=>e===t[r])}function an(n,t){return n.reduce((e,r)=>{let o=t(r);return (e[o]=e[o]||[]).push(r),e},{})}function fn(n,{name:t="label",value:e="",valueKey:r="value"}={}){return [{[t]:"\u5168\u90E8",[r]:e},...n]}function O(n,t,e="children",r=true){return n.map(o=>{let u={...o};return Object.entries(t).forEach(([c,T])=>{d(u,c)&&(u[T]=u[c],r&&delete u[c]);}),Array.isArray(u[e])&&(u[e]=O(u[e],t,e,r)),u})}function L(n,t,e="children"){return n.map(r=>{let o=r[e]?L(r[e],t,e):[];return t(r,o)})}function cn(n,t){let e={};for(let r of n){let o=r[t];o&&(e[o]=r);}return e}i.locale("zh-cn");i.extend(U);i.extend(A);i.extend(N);i.extend(S);function bn(n){return i(n)}function hn(n){if(!p(n)||n.toString().length!==13)return false;let t=new Date(n);return !a(t.getTime())}function s(n){return p(n)&&String(n).length===10?n*1e3:n}function E(n,t="YYYY-MM-DD"){return i(s(n)).format(t)}function Dn(n){return E(n,"YYYY-MM-DD HH:mm:ss")}function kn(){return Date.now()}function wn(n){let t=i(n);if(!t.isValid())throw new TypeError("\u65E0\u6548\u7684\u65E5\u671F\u683C\u5F0F");return t.toDate()}function Rn(n,t,e="day"){return i(s(n)).diff(i(s(t)),e)}function l(n,t,e="day"){return i(s(n)).add(t,e).toDate()}function Mn(n,t){return l(s(n),t,"day")}function On(n,t){return l(s(n),t,"month")}function Ln(n,t){return l(s(n),t,"year")}function Sn(n,t=false){let r=i(s(n)).day();return t?r===0?6:r-1:r}function Nn(n,t,e){let r=i(s(n));return r.isAfter(i(s(t)))&&r.isBefore(i(s(e)))}function An(n,t){return i(new Date(n,t,1)).daysInMonth()}function Un(n,t){return n=s(n),t=t&&s(t),t?i(n).from(i(t)):i(n).fromNow()}function En(n,t){return i(s(n)).startOf(t).toDate()}function jn(n,t){return i(s(n)).endOf(t).toDate()}function Kn(n){let t=i(s(n)),e=i();return t.isSame(e,"day")?`\u4ECA\u5929 ${t.format("HH:mm")}`:t.isSame(e.subtract(1,"day"),"day")?`\u6628\u5929 ${t.format("HH:mm")}`:t.isSame(e.add(1,"day"),"day")?`\u660E\u5929 ${t.format("HH:mm")}`:t.isSame(e,"year")?t.format("M\u6708D\u65E5 HH:mm"):t.format("YYYY\u5E74M\u6708D\u65E5 HH:mm")}function j(n,t=0){let e=10**t;return Math.round(n*e)/e}function $n(n,t){return n.toLocaleString(t)}function Hn(n,t={}){let{currency:e="CNY",locale:r="zh-CN",minimumFractionDigits:o=2,maximumFractionDigits:u=2}=t;return new Intl.NumberFormat(r,{style:"currency",currency:e,minimumFractionDigits:o,maximumFractionDigits:u}).format(n)}function Yn(n,t,e){return Math.min(Math.max(n,t),e)}function Cn(n,t){return n=Math.ceil(n),t=Math.floor(t),Math.floor(Math.random()*(t-n+1))+n}function K(n){return n%2===0}function Vn(n){return !K(n)}function Fn(n,t,e=2){return t===0?0:j(n/t*100,e)}function In(n,t=2){return n?n>=1e4?`${(n/1e4).toFixed(t)}\u4E07`:n.toString():"0"}function zn(n){return new Promise(t=>setTimeout(t,n))}function vn(n){return n.length===0?n:n.charAt(0).toUpperCase()+n.slice(1)}function Zn(n){return n.replace(/([A-Z])([A-Z]+)([A-Z])/g,"$1$2-$3").replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function Wn(n){return n.replace(/-([a-z])/g,(t,e)=>e.toUpperCase())}function _n(n,t=50,e="..."){if(n.length<=t)return n;let r=t-e.length;return n.substring(0,r)+e}function Gn(n,t="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"){let e="",r=t.length;for(let o=0;o<n;o++)e+=t.charAt(Math.floor(Math.random()*r));return e}function Jn(n){let t={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;","/":"&#x2F;","`":"&#x60;","=":"&#x3D;"};return n.replace(/[&<>"'`=/]/g,e=>t[e]||e)}function Xn(n){try{return !!new URL(n)}catch{return false}}function nt(n){return /^[\w.%+-]+@[a-z0-9.-]+\.[a-z]{2,}$/i.test(n)}function tt(n){return n.trim().length===0}function et(n){let t=Number(n);return a(t)?n:`${n}rpx`}function rt(n,t){let e=Array.isArray(n)?n:n.value;return e.length?e.map(r=>typeof r[t]=="string"?{...r,[t]:r[t].replace(/&nbsp;/g,"\xA0\xA0")}:r):[]}function ut(n){if(!n)return "";let t=y(n);return t?`?${t}`:""}export{l as add,Mn as addDays,On as addMonths,Ln as addYears,fn as appendUniversalOption,cn as arrayToObject,Zn as camelToKebab,vn as capitalize,tn as chunk,Yn as clamp,s as convertToDayjsParam,bn as createDate,g as deepClone,M as deepMerge,zn as delay,Rn as diff,jn as endOf,et as ensureRpxUnit,Jn as escapeHtml,_ as filterObjectByKeys,rn as first,Hn as formatCurrency,E as formatDate,Dn as formatFullTime,Kn as formatHumanReadable,In as formatNumberWithTenThousand,$n as formatThousands,Un as fromNow,q as get,Sn as getDayOfWeek,An as getDaysInMonth,ut as getQueryStringify,an as groupBy,d as hasOwnProp,h as isArray,P as isBoolean,$ as isDate,Nn as isDateInRange,B as isEmpty,R as isEmptyObject,tt as isEmptyString,sn as isEqual,K as isEven,x as isFunction,C as isMap,hn as isMillisecondTimestamp,a as isNaN,k as isNull,w as isNullOrUndefined,p as isNumber,m as isObject,Vn as isOdd,f as isPlainObject,I as isPrimitive,Y as isPromise,H as isRegExp,V as isSet,b as isString,F as isSymbol,D as isUndefined,nt as isValidEmail,Xn as isValidUrl,Wn as kebabToCamel,en as last,W as merge,kn as now,y as objectToQueryString,Z as omit,wn as parseDate,Fn as percentage,v as pick,Cn as randomInt,Gn as randomString,X as remove,O as renameTreeNodes,rt as replaceNBSP,j as round,un as sample,on as shuffle,En as startOf,L as transformTree,_n as truncate,nn as unique};//# sourceMappingURL=index.js.map
1
+ import i from'dayjs';import N from'dayjs/plugin/isBetween';import A from'dayjs/plugin/isSameOrAfter';import U from'dayjs/plugin/isSameOrBefore';import E from'dayjs/plugin/relativeTime';import'dayjs/locale/zh-cn';function p(n){return typeof n=="string"}function m(n){return typeof n=="number"&&!s(n)}function $(n){return typeof n=="boolean"}function y(n){return typeof n=="function"}function g(n){return n!==null&&typeof n=="object"}function D(n){return Array.isArray(n)}function H(n){return n instanceof Date}function Y(n){return n instanceof RegExp}function C(n){return g(n)&&y(n.then)&&y(n.catch)}function V(n){return n instanceof Map}function B(n){return n instanceof Set}function F(n){return typeof n=="symbol"}function I(n){return n===null||typeof n!="object"&&typeof n!="function"}function k(n){return typeof n>"u"}function w(n){return n===null}function R(n){return w(n)||k(n)}function M(n){return g(n)&&Object.keys(n).length===0}function z(n){return R(n)?true:p(n)?n.trim().length===0:D(n)?n.length===0:g(n)?M(n):false}function s(n){return Number.isNaN(n)}function f(n){if(typeof n!="object"||n===null)return false;let t=Object.getPrototypeOf(n);return t===Object.prototype||t===null}function d(n,t){return Object.prototype.hasOwnProperty.call(n,t)}function l(n){if(n===null||typeof n!="object")return n;if(n instanceof Date)return new Date(n.getTime());if(n instanceof RegExp)return new RegExp(n.source,n.flags);if(Array.isArray(n))return n.map(e=>l(e));let t={};return Object.keys(n).forEach(e=>{t[e]=l(n[e]);}),t}function Z(n,t,e){let r=t.split("."),o=n;for(let u of r){if(o==null)return e;o=o[u];}return o===void 0?e:o}function v(n,t){return t.reduce((e,r)=>(r in n&&(e[r]=n[r]),e),{})}function W(n,t){let e={...n};return t.forEach(r=>{delete e[r];}),e}function T(n){return Object.entries(n).filter(([t,e])=>e!=null).map(([t,e])=>Array.isArray(e)?e.map(r=>`${encodeURIComponent(t)}=${encodeURIComponent(String(r))}`).join("&"):`${encodeURIComponent(t)}=${encodeURIComponent(String(e))}`).join("&")}function _(...n){return Object.assign({},...n)}function O(...n){let t={};return n.forEach(e=>{f(e)&&Object.keys(e).forEach(r=>{let o=e[r],u=t[r];f(o)&&f(u)?t[r]=O(u,o):t[r]=l(o);});}),t}function G(n,t,e={}){return t.reduce((r,o)=>{if(d(n,o)){let u=e[o]||o;r[u]=n[o];}return r},{})}function nn(n){return n.length===0?n:n.charAt(0).toUpperCase()+n.slice(1)}function tn(n){return n.replace(/([A-Z])([A-Z]+)([A-Z])/g,"$1$2-$3").replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function en(n){return n.replace(/-([a-z])/g,(t,e)=>e.toUpperCase())}function rn(n,t=50,e="..."){if(n.length<=t)return n;let r=t-e.length;return n.substring(0,r)+e}function on(n,t="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"){let e="",r=t.length;for(let o=0;o<n;o++)e+=t.charAt(Math.floor(Math.random()*r));return e}function un(n){let t={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;","/":"&#x2F;","`":"&#x60;","=":"&#x3D;"};return n.replace(/[&<>"'`=/]/g,e=>t[e]||e)}function an(n){try{return !!new URL(n)}catch{return false}}function sn(n){return /^[\w.%+-]+@[a-z0-9.-]+\.[a-z]{2,}$/i.test(n)}function fn(n){return n.trim().length===0}function cn(n){let t=Number(n);return s(t)?n:`${n}rpx`}function b(n){return p(n)?n.replace(/&nbsp;/g," ").replace(/\u00A0/g," "):n}function ln(n,t){return n.filter(e=>e!==t)}function dn(n){return Array.from(new Set(n))}function xn(n,t){if(t<=0)return [n];let e=[];for(let r=0;r<n.length;r+=t)e.push(n.slice(r,r+t));return e}function yn(n){return n.length>0?n[n.length-1]:void 0}function Tn(n){return n.length>0?n[0]:void 0}function bn(n){let t=[...n];for(let e=t.length-1;e>0;e--){let r=Math.floor(Math.random()*(e+1));[t[e],t[r]]=[t[r],t[e]];}return t}function hn(n){if(n.length===0)return;let t=Math.floor(Math.random()*n.length);return n[t]}function Dn(n,t){return n.length!==t.length?false:n.every((e,r)=>e===t[r])}function kn(n,t){return n.reduce((e,r)=>{let o=t(r);return (e[o]=e[o]||[]).push(r),e},{})}function wn(n,{name:t="label",value:e="",valueKey:r="value"}={}){return [{[t]:"\u5168\u90E8",[r]:e},...n]}function S(n,t,e="children",r=true){return n.map(o=>{let u={...o};return Object.entries(t).forEach(([c,h])=>{d(u,c)&&(u[h]=u[c],r&&delete u[c]);}),Array.isArray(u[e])&&(u[e]=S(u[e],t,e,r)),u})}function L(n,t,e="children"){return n.map(r=>{let o=r[e]?L(r[e],t,e):[];return t(r,o)})}function Rn(n,t){let e={};for(let r of n){let o=r[t];o&&(e[o]=r);}return e}function Mn(n,t){return n.length?n.map(e=>typeof e[t]=="string"?{...e,[t]:b(e[t])}:e):[]}i.locale("zh-cn");i.extend(E);i.extend(U);i.extend(A);i.extend(N);function jn(n){return i(n)}function Kn(n){if(!m(n)||n.toString().length!==13)return false;let t=new Date(n);return !s(t.getTime())}function a(n){return m(n)&&String(n).length===10?n*1e3:n}function P(n,t="YYYY-MM-DD"){return i(a(n)).format(t)}function $n(n){return P(n,"YYYY-MM-DD HH:mm:ss")}function Hn(){return Date.now()}function Yn(n){let t=i(n);if(!t.isValid())throw new TypeError("\u65E0\u6548\u7684\u65E5\u671F\u683C\u5F0F");return t.toDate()}function Cn(n,t,e="day"){return i(a(n)).diff(i(a(t)),e)}function x(n,t,e="day"){return i(a(n)).add(t,e).toDate()}function Vn(n,t){return x(a(n),t,"day")}function Bn(n,t){return x(a(n),t,"month")}function Fn(n,t){return x(a(n),t,"year")}function In(n,t=false){let r=i(a(n)).day();return t?r===0?6:r-1:r}function zn(n,t,e){let r=i(a(n));return r.isAfter(i(a(t)))&&r.isBefore(i(a(e)))}function Qn(n,t){return i(new Date(n,t,1)).daysInMonth()}function qn(n,t){return n=a(n),t=t&&a(t),t?i(n).from(i(t)):i(n).fromNow()}function Zn(n,t){return i(a(n)).startOf(t).toDate()}function vn(n,t){return i(a(n)).endOf(t).toDate()}function Wn(n){let t=i(a(n)),e=i();return t.isSame(e,"day")?`\u4ECA\u5929 ${t.format("HH:mm")}`:t.isSame(e.subtract(1,"day"),"day")?`\u6628\u5929 ${t.format("HH:mm")}`:t.isSame(e.add(1,"day"),"day")?`\u660E\u5929 ${t.format("HH:mm")}`:t.isSame(e,"year")?t.format("M\u6708D\u65E5 HH:mm"):t.format("YYYY\u5E74M\u6708D\u65E5 HH:mm")}function j(n,t=0){let e=10**t;return Math.round(n*e)/e}function Gn(n,t){return n.toLocaleString(t)}function Jn(n,t={}){let{currency:e="CNY",locale:r="zh-CN",minimumFractionDigits:o=2,maximumFractionDigits:u=2}=t;return new Intl.NumberFormat(r,{style:"currency",currency:e,minimumFractionDigits:o,maximumFractionDigits:u}).format(n)}function Xn(n,t,e){return Math.min(Math.max(n,t),e)}function nt(n,t){return n=Math.ceil(n),t=Math.floor(t),Math.floor(Math.random()*(t-n+1))+n}function K(n){return n%2===0}function tt(n){return !K(n)}function et(n,t,e=2){return t===0?0:j(n/t*100,e)}function rt(n,t=2){return n?n>=1e4?`${(n/1e4).toFixed(t)}\u4E07`:n.toString():"0"}function it(n){return new Promise(t=>setTimeout(t,n))}function st(n){if(!n)return "";let t=T(n);return t?`?${t}`:""}export{x as add,Vn as addDays,Bn as addMonths,Fn as addYears,wn as appendUniversalOption,Mn as arrayReplaceNBSP,Rn as arrayToObject,tn as camelToKebab,nn as capitalize,xn as chunk,Xn as clamp,a as convertToDayjsParam,jn as createDate,l as deepClone,O as deepMerge,it as delay,Cn as diff,vn as endOf,cn as ensureRpxUnit,un as escapeHtml,G as filterObjectByKeys,Tn as first,Jn as formatCurrency,P as formatDate,$n as formatFullTime,Wn as formatHumanReadable,rt as formatNumberWithTenThousand,Gn as formatThousands,qn as fromNow,Z as get,In as getDayOfWeek,Qn as getDaysInMonth,st as getQueryStringify,kn as groupBy,d as hasOwnProp,D as isArray,$ as isBoolean,H as isDate,zn as isDateInRange,z as isEmpty,M as isEmptyObject,fn as isEmptyString,Dn as isEqual,K as isEven,y as isFunction,V as isMap,Kn as isMillisecondTimestamp,s as isNaN,w as isNull,R as isNullOrUndefined,m as isNumber,g as isObject,tt as isOdd,f as isPlainObject,I as isPrimitive,C as isPromise,Y as isRegExp,B as isSet,p as isString,F as isSymbol,k as isUndefined,sn as isValidEmail,an as isValidUrl,en as kebabToCamel,yn as last,_ as merge,Hn as now,T as objectToQueryString,W as omit,Yn as parseDate,et as percentage,v as pick,nt as randomInt,on as randomString,ln as remove,S as renameTreeNodes,b as replaceNBSP,j as round,hn as sample,bn as shuffle,Zn as startOf,L as transformTree,rn as truncate,dn as unique};//# sourceMappingURL=index.js.map
2
2
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../packages/is/index.ts","../packages/object/index.ts","../packages/array/index.ts","../packages/date/index.ts","../packages/number/index.ts","../packages/promise/index.ts","../packages/string/index.ts","../packages/url/index.ts"],"names":["isString","val","isNumber","isNaN","isBoolean","isFunction","isObject","isArray","isDate","isRegExp","isPromise","isMap","isSet","isSymbol","isPrimitive","isUndefined","isNull","isNullOrUndefined","isEmptyObject","isEmpty","value","isPlainObject","proto","hasOwnProp","obj","prop","deepClone","item","cloned","key","get","path","defaultValue","keys","result","pick","omit","objectToQueryString","_","merge","objects","deepMerge","sourceValue","targetValue","filterObjectByKeys","originalObject","keysArray","keyMapping","newObject","newKey","remove","array","i","unique","chunk","size","last","first","shuffle","j","sample","index","isEqual","a","b","groupBy","keyFn","appendUniversalOption","options","name","valueKey","renameTreeNodes","tree","renameMap","childKey","deleteOldKeys","node","newNode","oldKey","transformTree","transformer","children","arrayToObject","arr","K","dayjs","relativeTime","isSameOrBefore","isSameOrAfter","isBetween","createDate","date","isMillisecondTimestamp","convertToDayjsParam","formatDate","format","formatFullTime","now","parseDate","dateStr","d","diff","date1","date2","unit","add","amount","addDays","days","addMonths","months","addYears","years","getDayOfWeek","startOnMonday","day","isDateInRange","startDate","endDate","getDaysInMonth","year","month","fromNow","baseDate","startOf","endOf","formatHumanReadable","round","num","precision","factor","formatThousands","locale","formatCurrency","currency","minimumFractionDigits","maximumFractionDigits","clamp","min","max","randomInt","isEven","isOdd","percentage","total","formatNumberWithTenThousand","fractionDigits","delay","ms","resolve","capitalize","str","camelToKebab","kebabToCamel","char","truncate","length","ellipsis","truncatedLength","randomString","chars","charsLength","escapeHtml","html","entityMap","s","isValidUrl","url","isValidEmail","email","isEmptyString","ensureRpxUnit","replaceNBSP","tableData","unwrappedData","getQueryStringify","params","queryString"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * @module 类型检查\n * @description 提供各种数据类型检查函数,用于判断值的类型、判断对象特性等\n */\n\n/**\n * 检查值是否为字符串类型\n * @param val 要检查的值\n * @returns 如果是字符串则返回 true,否则返回 false\n * @group Is\n * @example\n * ```ts\n * isString('hello') // true\n * isString(123) // false\n * isString(new String('hello')) // false(注意:包装对象不是原始字符串类型)\n * ```\n */\nexport function isString(val: unknown): val is string {\n return typeof val === 'string'\n}\n\n/**\n * 检查值是否为数字类型\n * @param val 要检查的值\n * @returns 如果是数字则返回 true,否则返回 false(NaN 会返回 false)\n * @group Is\n * @example\n * ```ts\n * isNumber(123) // true\n * isNumber(-45.67) // true\n * isNumber('123') // false\n * isNumber(NaN) // false\n * isNumber(Infinity) // true\n * ```\n */\nexport function isNumber(val: unknown): val is number {\n return typeof val === 'number' && !isNaN(val)\n}\n\n/**\n * 检查值是否为布尔类型\n * @param val 要检查的值\n * @returns 如果是布尔值则返回 true,否则返回 false\n * @group Is\n * @example\n * ```ts\n * isBoolean(true) // true\n * isBoolean(false) // true\n * isBoolean(0) // false\n * isBoolean('false') // false\n * isBoolean(new Boolean(true)) // false(包装对象不是原始布尔类型)\n * ```\n */\nexport function isBoolean(val: unknown): val is boolean {\n return typeof val === 'boolean'\n}\n\n/**\n * 检查值是否为函数类型\n * @param val 要检查的值\n * @returns 如果是函数则返回 true,否则返回 false\n * @group Is\n * @example\n * ```ts\n * isFunction(() => {}) // true\n * isFunction(function() {}) // true\n * isFunction(class {}) // true\n * isFunction(Math.sin) // true\n * isFunction({}) // false\n * ```\n */\nexport function isFunction(val: unknown): val is ((...args: any[]) => any) {\n return typeof val === 'function'\n}\n\n/**\n * 检查值是否为对象类型(不包括 null)\n * @param val 要检查的值\n * @returns 如果是对象则返回 true,否则返回 false\n * @group Is\n * @example\n * ```ts\n * isObject({}) // true\n * isObject([]) // true(数组也是对象)\n * isObject(new Date()) // true\n * isObject(null) // false\n * isObject(undefined) // false\n * isObject(123) // false\n * ```\n */\nexport function isObject(val: unknown): val is Record<any, any> {\n return val !== null && typeof val === 'object'\n}\n\n/**\n * 检查值是否为数组类型\n * @param val 要检查的值\n * @returns 如果是数组则返回 true,否则返回 false\n * @group Is\n * @example\n * ```ts\n * isArray([]) // true\n * isArray([1, 2, 3]) // true\n * isArray(new Array()) // true\n * isArray({}) // false\n * isArray('abc') // false\n * ```\n */\nexport function isArray(val: unknown): val is any[] {\n return Array.isArray(val)\n}\n\n/**\n * 检查值是否为日期类型\n * @param val 要检查的值\n * @returns 如果是日期对象则返回 true,否则返回 false\n * @group Is\n * @example\n * ```ts\n * isDate(new Date()) // true\n * isDate(Date.now()) // false(时间戳是数字,不是日期对象)\n * isDate('2023-05-15') // false(日期字符串不是日期对象)\n * ```\n */\nexport function isDate(val: unknown): val is Date {\n return val instanceof Date\n}\n\n/**\n * 检查值是否为正则表达式\n * @param val 要检查的值\n * @returns 如果是正则表达式则返回 true,否则返回 false\n * @group Is\n * @example\n * ```ts\n * isRegExp(/abc/) // true\n * isRegExp(new RegExp('abc')) // true\n * isRegExp('/abc/') // false(字符串不是正则表达式)\n * isRegExp({}) // false\n * ```\n */\nexport function isRegExp(val: unknown): val is RegExp {\n return val instanceof RegExp\n}\n\n/**\n * 检查值是否为 Promise\n * @param val 要检查的值\n * @returns 如果是 Promise 则返回 true,否则返回 false\n * @group Is\n * @example\n * ```ts\n * isPromise(Promise.resolve()) // true\n * isPromise(new Promise(() => {})) // true\n * isPromise({ then: () => {}, catch: () => {} }) // true(类 Promise 对象也会返回 true)\n * isPromise({}) // false\n * isPromise(null) // false\n * ```\n */\nexport function isPromise<T = any>(val: unknown): val is Promise<T> {\n return isObject(val) && isFunction((val as any).then) && isFunction((val as any).catch)\n}\n\n/**\n * 检查值是否为 Map\n * @param val 要检查的值\n * @returns 如果是 Map 则返回 true,否则返回 false\n * @group Is\n * @example\n * ```ts\n * isMap(new Map()) // true\n * isMap(new WeakMap()) // false\n * isMap({}) // false\n * ```\n */\nexport function isMap<K = any, V = any>(val: unknown): val is Map<K, V> {\n return val instanceof Map\n}\n\n/**\n * 检查值是否为 Set\n * @param val 要检查的值\n * @returns 如果是 Set 则返回 true,否则返回 false\n * @group Is\n * @example\n * ```ts\n * isSet(new Set()) // true\n * isSet(new WeakSet()) // false\n * isSet([]) // false\n * ```\n */\nexport function isSet<T = any>(val: unknown): val is Set<T> {\n return val instanceof Set\n}\n\n/**\n * 检查值是否为 Symbol\n * @param val 要检查的值\n * @returns 如果是 Symbol 则返回 true,否则返回 false\n * @group Is\n * @example\n * ```ts\n * isSymbol(Symbol('foo')) // true\n * isSymbol(Symbol.for('bar')) // true\n * isSymbol('symbol') // false\n * ```\n */\nexport function isSymbol(val: unknown): val is symbol {\n return typeof val === 'symbol'\n}\n\n/**\n * 检查值是否为原始类型(string、number、boolean、symbol、bigint、null、undefined)\n * @param val 要检查的值\n * @returns 如果是原始类型则返回 true,否则返回 false\n * @group Is\n * @example\n * ```ts\n * isPrimitive('hello') // true\n * isPrimitive(123) // true\n * isPrimitive(true) // true\n * isPrimitive(Symbol()) // true\n * isPrimitive(null) // true\n * isPrimitive(undefined) // true\n * isPrimitive(BigInt(123)) // true\n * isPrimitive({}) // false\n * isPrimitive([]) // false\n * isPrimitive(() => {}) // false\n * ```\n */\nexport function isPrimitive(val: unknown): boolean {\n return val === null || (typeof val !== 'object' && typeof val !== 'function')\n}\n\n/**\n * 检查值是否为 undefined\n * @param val 要检查的值\n * @returns 如果是 undefined 则返回 true,否则返回 false\n * @group Is\n * @example\n * ```ts\n * isUndefined(undefined) // true\n * isUndefined(void 0) // true\n * isUndefined(null) // false\n * isUndefined('') // false\n * ```\n */\nexport function isUndefined(val: unknown): val is undefined {\n return typeof val === 'undefined'\n}\n\n/**\n * 检查值是否为 null\n * @param val 要检查的值\n * @returns 如果是 null 则返回 true,否则返回 false\n * @group Is\n * @example\n * ```ts\n * isNull(null) // true\n * isNull(undefined) // false\n * isNull(0) // false\n * isNull('') // false\n * ```\n */\nexport function isNull(val: unknown): val is null {\n return val === null\n}\n\n/**\n * 检查值是否为 null 或 undefined\n * @param val 要检查的值\n * @returns 如果是 null 或 undefined 则返回 true,否则返回 false\n * @group Is\n * @example\n * ```ts\n * isNullOrUndefined(null) // true\n * isNullOrUndefined(undefined) // true\n * isNullOrUndefined(void 0) // true\n * isNullOrUndefined('') // false\n * isNullOrUndefined(0) // false\n * ```\n */\nexport function isNullOrUndefined(val: unknown): val is null | undefined {\n return isNull(val) || isUndefined(val)\n}\n\n/**\n * 检查对象是否为空对象(没有自身可枚举属性)\n * @param val 要检查的值\n * @returns 如果是空对象则返回 true,否则返回 false;如果不是对象类型则返回 false\n * @group Is\n * @example\n * ```ts\n * isEmptyObject({}) // true\n * isEmptyObject({ a: 1 }) // false\n * isEmptyObject([]) // true(空数组也会返回 true)\n * isEmptyObject(null) // false(不是对象)\n * isEmptyObject(Object.create(null)) // true\n * isEmptyObject(Object.create({ toString: () => '' })) // true(不包括继承的属性)\n * ```\n */\nexport function isEmptyObject(val: unknown): boolean {\n return isObject(val) && Object.keys(val).length === 0\n}\n\n/**\n * 检查值是否为空(null、undefined、空字符串、空数组或空对象)\n * @param val 要检查的值\n * @returns 如果是空值则返回 true,否则返回 false\n * @group Is\n * @example\n * ```ts\n * isEmpty(null) // true\n * isEmpty(undefined) // true\n * isEmpty('') // true\n * isEmpty(' ') // true(空白字符串也视为空)\n * isEmpty([]) // true\n * isEmpty({}) // true\n * isEmpty(0) // false\n * isEmpty(false) // false\n * isEmpty(' hello ') // false\n * ```\n */\nexport function isEmpty(val: unknown): boolean {\n if (isNullOrUndefined(val))\n return true\n if (isString(val))\n return val.trim().length === 0\n if (isArray(val))\n return val.length === 0\n if (isObject(val))\n return isEmptyObject(val)\n return false\n}\n\n/**\n * 检查值是否为 NaN\n * @param value 要检查的值\n * @returns 如果值是 NaN 则返回 true,否则返回 false\n * @group Is\n * @example\n * ```ts\n * isNaN(NaN) // true\n * isNaN(Number('abc')) // true\n * isNaN(0 / 0) // true\n * isNaN(123) // false\n * isNaN('123') // false(不同于全局 isNaN,此函数不会先尝试转换为数字)\n * ```\n */\nexport function isNaN(value: unknown): boolean {\n return Number.isNaN(value)\n}\n\n/**\n * 检查值是否为普通对象(由 Object 构造函数创建或对象字面量)\n *\n * @param {unknown} value - 要检查的值\n * @returns {boolean} 如果值是普通对象则返回 true,否则返回 false\n *\n * @group Is\n * @example\n * ```ts\n * isPlainObject({}) // true\n * isPlainObject({ a: 1 }) // true\n * isPlainObject(new Date()) // false\n * isPlainObject([]) // false\n * isPlainObject(null) // false\n * ```\n */\nexport function isPlainObject(value: unknown): value is Record<string, any> {\n if (typeof value !== 'object' || value === null) {\n return false\n }\n\n const proto = Object.getPrototypeOf(value)\n return proto === Object.prototype || proto === null\n}\n","/**\n * @module 对象操作\n * @description 提供各种对象处理函数,包括对象深拷贝、合并、转换等实用功能\n */\n\nimport { isPlainObject } from '../is'\n\n/**\n * 检查对象是否具有指定的自有属性。\n *\n * @param {object} obj - 需要检查的对象\n * @param {string | symbol} prop - 需要检查的属性键\n * @returns {boolean} 如果对象具有该自有属性,则返回 true,否则返回 false\n * @group Object\n * @example\n * ```ts\n * const obj = { name: 'Tom', age: 25 }\n * hasOwnProp(obj, 'name') // true\n * hasOwnProp(obj, 'toString') // false,toString 是继承的属性\n * ```\n */\nexport function hasOwnProp(obj: object, prop: string | symbol): boolean {\n return Object.prototype.hasOwnProperty.call(obj, prop)\n}\n\n/**\n * 深拷贝对象,支持基本类型、数组、对象、日期和正则表达式\n * @param obj 要拷贝的对象\n * @returns 深拷贝后的对象,与原对象完全独立\n * @group Object\n * @example\n * ```ts\n * const original = { a: 1, b: { c: 2 }, d: [1, 2, 3], e: new Date() }\n * const copy = deepClone(original)\n * copy.b.c = 100\n * console.log(original.b.c) // 2,原对象不受影响\n *\n * // 支持日期对象\n * const date = new Date()\n * const clonedDate = deepClone(date)\n * console.log(date === clonedDate) // false,不是同一引用\n * ```\n */\nexport function deepClone<T>(obj: T): T {\n if (obj === null || typeof obj !== 'object') {\n return obj\n }\n\n if (obj instanceof Date) {\n return new Date(obj.getTime()) as unknown as T\n }\n\n if (obj instanceof RegExp) {\n return new RegExp(obj.source, obj.flags) as unknown as T\n }\n\n if (Array.isArray(obj)) {\n return obj.map(item => deepClone(item)) as unknown as T\n }\n\n const cloned: Record<string, any> = {}\n Object.keys(obj as Record<string, any>).forEach((key) => {\n cloned[key] = deepClone((obj as Record<string, any>)[key])\n })\n\n return cloned as T\n}\n\n/**\n * 从对象中获取指定路径的值,支持点分隔的嵌套路径\n * @param obj 源对象\n * @param path 属性路径,如 'user.address.street'\n * @param defaultValue 默认值,当路径不存在时返回\n * @returns 路径对应的值,如果路径不存在则返回默认值\n * @group Object\n * @example\n * ```ts\n * const obj = { user: { profile: { name: 'Tom', age: 25 }, roles: ['admin'] } }\n *\n * get(obj, 'user.profile.name') // 'Tom'\n * get(obj, 'user.roles.0') // 'admin'\n * get(obj, 'user.settings', { theme: 'dark' }) // { theme: 'dark' }(路径不存在,返回默认值)\n * get(obj, 'user.profile.gender') // undefined(路径不存在且没提供默认值)\n * get(obj, 'user.profile.gender', 'unknown') // 'unknown'(使用默认值)\n * ```\n */\nexport function get<T = any>(obj: Record<string, any>, path: string, defaultValue?: T): T | undefined {\n const keys = path.split('.')\n let result = obj\n\n for (const key of keys) {\n if (result === undefined || result === null) {\n return defaultValue\n }\n result = result[key]\n }\n\n return (result === undefined) ? defaultValue : result as T\n}\n\n/**\n * 从对象中选择指定的属性,创建一个新对象\n * @param obj 原始对象\n * @param keys 要选择的键数组\n * @returns 包含指定键的新对象\n * @group Object\n * @example\n * ```ts\n * @group Object\n * const user = { id: 1, name: 'Tom', age: 25, email: 'tom@example.com' }\n *\n * @group Object\n * pick(user, ['name', 'email']) // { name: 'Tom', email: 'tom@example.com' }\n * pick(user, ['name', 'gender']) // { name: 'Tom' }(不存在的键会被忽略)\n * pick(user, []) // {}(空数组返回空对象)\n * ```\n */\nexport function pick<T extends Record<string, any>, K extends keyof T>(obj: T, keys: K[]): Pick<T, K> {\n return keys.reduce((result, key) => {\n if (key in obj) {\n result[key] = obj[key]\n }\n return result\n }, {} as Pick<T, K>)\n}\n\n/**\n * 从对象中排除指定的属性,创建一个新对象\n * @param obj 原始对象\n * @param keys 要排除的键数组\n * @returns 不包含指定键的新对象\n * @group Object\n * @example\n * ```ts\n * const user = { id: 1, name: 'Tom', age: 25, password: '123456' }\n *\n * omit(user, ['password']) // { id: 1, name: 'Tom', age: 25 }\n * omit(user, ['id', 'age']) // { name: 'Tom', password: '123456' }\n * omit(user, ['nonExistent']) // 原对象的拷贝,不存在的键会被忽略\n * ```\n */\nexport function omit<T extends Record<string, any>, K extends keyof T>(obj: T, keys: K[]): Omit<T, K> {\n const result = { ...obj }\n keys.forEach((key) => {\n delete result[key]\n })\n return result\n}\n\n/**\n * 将对象转换为 URL 查询字符串\n * @param obj 要转换的对象\n * @returns 格式化后的查询字符串(不包含前导?)\n * @group Object\n * @example\n * ```ts\n * objectToQueryString({ name: 'Tom', age: 25 }) // 'name=Tom&age=25'\n * objectToQueryString({ search: 'hello world', page: 1 }) // 'search=hello%20world&page=1'\n * objectToQueryString({ tags: ['js', 'ts'] }) // 'tags=js&tags=ts'\n * objectToQueryString({ name: 'Tom', empty: null }) // 'name=Tom'(null 和 undefined 会被过滤)\n * ```\n */\nexport function objectToQueryString(obj: Record<string, any>): string {\n return Object.entries(obj)\n .filter(([_, value]) => value !== undefined && value !== null)\n .map(([key, value]) => {\n if (Array.isArray(value)) {\n return value.map(item => `${encodeURIComponent(key)}=${encodeURIComponent(String(item))}`).join('&')\n }\n return `${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`\n })\n .join('&')\n}\n\n/**\n * 合并多个对象,后面的对象的属性会覆盖前面的\n * @param objects 要合并的对象数组\n * @returns 合并后的新对象\n * @group Object\n * @example\n * ```ts\n * merge({ a: 1 }, { b: 2 }) // { a: 1, b: 2 }\n * merge({ a: 1 }, { a: 2, b: 2 }) // { a: 2, b: 2 }(后面对象的属性会覆盖前面的)\n * merge({ a: { x: 1 } }, { a: { y: 2 } }) // { a: { y: 2 } }(不是深度合并)\n * merge({}, { a: 1 }, { b: 2 }, { c: 3 }) // { a: 1, b: 2, c: 3 }\n * ```\n */\nexport function merge<T extends Record<string, any>>(...objects: T[]): T {\n return Object.assign({}, ...objects)\n}\n\n/**\n * 深度合并多个对象,会递归合并嵌套对象\n * @param objects 要合并的对象数组\n * @returns 深度合并后的新对象\n * @group Object\n * @example\n * ```ts\n * deepMerge({ a: { x: 1 } }, { a: { y: 2 } }) // { a: { x: 1, y: 2 } }\n * deepMerge({ a: 1 }, { b: 2 }) // { a: 1, b: 2 }\n * deepMerge({ a: [1, 2] }, { a: [3, 4] }) // { a: [3, 4] }(数组会被替换,不会合并)\n * deepMerge({}, { a: null }, { a: { b: 2 } }) // { a: { b: 2 } }(null 会被后面的对象覆盖)\n * ```\n */\nexport function deepMerge(...objects: Record<string, any>[]): Record<string, any> {\n const result: Record<string, any> = {}\n\n objects.forEach((obj) => {\n if (!isPlainObject(obj))\n return\n\n Object.keys(obj).forEach((key) => {\n const sourceValue = obj[key]\n const targetValue = result[key]\n\n // 如果两个值都是对象,就递归合并\n if (isPlainObject(sourceValue) && isPlainObject(targetValue)) {\n result[key] = deepMerge(targetValue, sourceValue)\n }\n else {\n // 否则直接覆盖\n result[key] = deepClone(sourceValue)\n }\n })\n })\n\n return result\n}\n\n/**\n * 根据传入的键数组和键名映射对象过滤并重命名对象,返回一个新对象\n * @param originalObject 要过滤的原始对象\n * @param keysArray 要保留的键名数组\n * @param keyMapping 可选的键名映射对象,格式为 { 原键名: 新键名 }\n * @returns 返回一个新对象,其中只包含原对象中匹配的键值对,并根据映射重命名键\n * @group Object\n * @example\n * ```ts\n * const originalObject = { name: \"John\", age: 30, gender: \"male\", country: \"USA\" }\n * const keysToFilter = [\"name\", \"country\"]\n * const keyMapping = { name: \"fullName\", country: \"location\" }\n * const result = filterObjectByKeys(originalObject, keysToFilter, keyMapping)\n * // 结果: { fullName: 'John', location: 'USA' }\n * ```\n */\nexport function filterObjectByKeys(\n originalObject: Record<string, any>,\n keysArray: string[],\n keyMapping: Record<string, string> = {},\n): Record<string, any> {\n return keysArray.reduce((newObject: Record<string, any>, key: string) => {\n if (hasOwnProp(originalObject, key)) {\n const newKey = keyMapping[key] || key // 如果有映射,就用新键名,否则用原键名\n newObject[newKey] = originalObject[key]\n }\n return newObject\n }, {})\n}\n","/**\n * @module 数组操作\n * @description 提供各种数组处理函数,包括数组转换、查询、过滤等实用功能。这些函数都不会修改原始数组,而是返回新的数组或值。\n */\n\nimport { hasOwnProp } from '../object'\n\n/**\n * 从数组中移除指定的项\n * @param array 原始数组\n * @param item 要移除的项\n * @returns 移除指定项后的新数组,不会修改原始数组\n * @group Array\n * @example\n * ```ts\n * const numbers = [1, 2, 3, 4, 5]\n * const newArray = remove(numbers, 3) // [1, 2, 4, 5]\n * console.log(numbers) // 原数组不变: [1, 2, 3, 4, 5]\n *\n * // 移除字符串\n * const fruits = ['苹果', '香蕉', '橙子']\n * const newFruits = remove(fruits, '香蕉') // ['苹果', '橙子']\n * ```\n */\nexport function remove<T>(array: T[], item: T): T[] {\n return array.filter(i => i !== item)\n}\n\n/**\n * 数组去重,移除数组中的重复元素\n * @param array 原始数组\n * @returns 去重后的新数组,保持原始顺序\n * @group Array\n * @example\n * ```ts\n * const numbers = [1, 2, 2, 3, 3, 4, 5, 5]\n * const uniqueArray = unique(numbers) // [1, 2, 3, 4, 5]\n *\n * // 对象数组会基于引用去重,内容相同但引用不同的对象会被视为不同元素\n * const objArray = [{id: 1}, {id: 2}, {id: 1}]\n * const uniqueObjArray = unique(objArray) // [{id: 1}, {id: 2}, {id: 1}]\n * ```\n */\nexport function unique<T>(array: T[]): T[] {\n return Array.from(new Set(array))\n}\n\n/**\n * 将数组分成指定大小的块\n * @param array 原始数组\n * @param size 每个块的大小,必须为正整数\n * @returns 二维数组,每个子数组最多包含 size 个元素\n * @group Array\n * @example\n * ```ts\n * const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n * const chunks = chunk(numbers, 3)\n * // 结果: [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]\n *\n * // 如果 size 小于等于 0,则返回包含原始数组的数组\n * chunk(numbers, 0) // [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]]\n * ```\n */\nexport function chunk<T>(array: T[], size: number): T[][] {\n if (size <= 0)\n return [array]\n\n const result: T[][] = []\n for (let i = 0; i < array.length; i += size) {\n result.push(array.slice(i, i + size))\n }\n\n return result\n}\n\n/**\n * 获取数组中的最后一个元素\n * @param array 数组\n * @returns 最后一个元素,如果数组为空则返回 undefined\n * @group Array\n * @example\n * ```ts\n * const numbers = [1, 2, 3, 4, 5]\n * const lastNumber = last(numbers) // 5\n *\n * const empty = []\n * const lastEmpty = last(empty) // undefined\n * ```\n */\nexport function last<T>(array: T[]): T | undefined {\n return array.length > 0 ? array[array.length - 1] : undefined\n}\n\n/**\n * 获取数组中的第一个元素\n * @param array 数组\n * @returns 第一个元素,如果数组为空则返回 undefined\n * @group Array\n * @example\n * ```ts\n * const numbers = [1, 2, 3, 4, 5]\n * const firstNumber = first(numbers) // 1\n *\n * const empty = []\n * const firstEmpty = first(empty) // undefined\n * ```\n */\nexport function first<T>(array: T[]): T | undefined {\n return array.length > 0 ? array[0] : undefined\n}\n\n/**\n * 随机打乱数组元素顺序\n * @param array 原始数组\n * @returns 打乱后的新数组,不会修改原始数组\n * @group Array\n * @example\n * ```ts\n * const numbers = [1, 2, 3, 4, 5]\n * const shuffled = shuffle(numbers)\n * // 可能的结果: [3, 1, 5, 2, 4]\n * console.log(numbers) // 原数组不变: [1, 2, 3, 4, 5]\n * ```\n */\nexport function shuffle<T>(array: T[]): T[] {\n const result = [...array]\n\n for (let i = result.length - 1; i > 0; i--) {\n const j = Math.floor(Math.random() * (i + 1));\n [result[i], result[j]] = [result[j] as T, result[i] as T]\n }\n\n return result\n}\n\n/**\n * 从数组中随机选择一个元素\n * @param array 数组\n * @returns 随机选择的元素,如果数组为空则返回 undefined\n * @group Array\n * @example\n * ```ts\n * const fruits = ['苹果', '香蕉', '橙子', '梨', '葡萄']\n * const randomFruit = sample(fruits)\n * // 可能返回: '香蕉'\n *\n * const empty = []\n * const emptyResult = sample(empty) // undefined\n * ```\n */\nexport function sample<T>(array: T[]): T | undefined {\n if (array.length === 0)\n return undefined\n const index = Math.floor(Math.random() * array.length)\n return array[index]\n}\n\n/**\n * 比较两个数组是否相等(元素顺序和值都相同)\n * @param a 第一个数组\n * @param b 第二个数组\n * @returns 如果两个数组长度相同且对应位置的元素全部相等则返回 true,否则返回 false\n * @group Array\n * @example\n * ```ts\n * isEqual([1, 2, 3], [1, 2, 3]) // true\n * isEqual([1, 2, 3], [1, 3, 2]) // false,顺序不同\n * isEqual([1, 2, 3], [1, 2]) // false,长度不同\n *\n * // 对象比较是基于引用的\n * const obj = { id: 1 }\n * isEqual([obj], [obj]) // true,同一个对象引用\n * isEqual([{ id: 1 }], [{ id: 1 }]) // false,不同对象引用\n * ```\n */\nexport function isEqual<T>(a: T[], b: T[]): boolean {\n if (a.length !== b.length)\n return false\n return a.every((item, index) => item === b[index])\n}\n\n/**\n * 根据条件对数组中的元素进行分组\n * @param array 原始数组\n * @param keyFn 用于生成分组键的函数,接收数组元素并返回用作分组键的值\n * @returns 分组后的对象,键为分组键,值为对应的元素数组\n * @group Array\n * @example\n * ```ts\n * const people = [\n * { name: '张三', age: 25 },\n * { name: '李四', age: 30 },\n * { name: '王五', age: 25 },\n * { name: '赵六', age: 30 }\n * ]\n *\n * // 按年龄分组\n * const groupedByAge = groupBy(people, person => person.age)\n * // 结果:\n * // {\n * // 25: [{ name: '张三', age: 25 }, { name: '王五', age: 25 }],\n * // 30: [{ name: '李四', age: 30 }, { name: '赵六', age: 30 }]\n * // }\n *\n * // 使用字符串键\n * const groupedByAgeRange = groupBy(people, person =>\n * person.age < 30 ? '青年' : '成年')\n * // 结果:\n * // {\n * // '青年': [{ name: '张三', age: 25 }, { name: '王五', age: 25 }],\n * // '成年': [{ name: '李四', age: 30 }, { name: '赵六', age: 30 }]\n * // }\n * ```\n */\nexport function groupBy<T, K extends string | number | symbol>(array: T[], keyFn: (item: T) => K): Record<K, T[]> {\n return array.reduce((result, item) => {\n const key = keyFn(item);\n (result[key] = result[key] || []).push(item)\n return result\n }, {} as Record<K, T[]>)\n}\n\n/**\n * 在选项数组前添加一个\"全部\"选项\n *\n * @param options - 原始选项数组\n * @param config - 配置选项\n * @param config.name - 选项标签的字段名 (默认为 'label')\n * @param config.value - \"全部\"选项的值 (默认为 '')\n * @param config.valueKey - 选项值的字段名 (默认为 'value')\n * @returns 添加了\"全部\"选项的新数组\n *\n * @group Array\n * @example\n * ```ts\n * // 基本用法\n * const options = [\n * { label: '选项1', value: 1 },\n * { label: '选项2', value: 2 }\n * ]\n * const result = appendUniversalOption(options)\n * // 结果: [\n * // { label: '全部', value: '' },\n * // { label: '选项1', value: 1 },\n * // { label: '选项2', value: 2 }\n * // ]\n *\n * // 自定义字段名和值\n * const customOptions = [\n * { text: '选项1', id: 1 },\n * { text: '选项2', id: 2 }\n * ]\n * const customResult = appendUniversalOption(customOptions, {\n * name: 'text',\n * valueKey: 'id',\n * value: 0\n * })\n * // 结果: [\n * // { text: '全部', id: 0 },\n * // { text: '选项1', id: 1 },\n * // { text: '选项2', id: 2 }\n * // ]\n * ```\n */\nexport function appendUniversalOption<T extends Record<string, any>, V = any>(\n options: T[],\n {\n name = 'label',\n value = '' as V,\n valueKey = 'value',\n }: {\n name?: string\n value?: V\n valueKey?: string\n } = {},\n): T[] {\n return [\n {\n [name]: '全部',\n [valueKey]: value,\n } as unknown as T,\n ...options,\n ]\n}\n\n/**\n * 递归重命名树形结构节点的属性。\n *\n * @param tree - 需要处理的树形数据(根节点数组)\n * @param renameMap - 属性重命名映射对象,格式为 `{ oldKey: newKey }`\n * @param childKey - 子节点的键名(默认为 `'children'`)\n * @param deleteOldKeys - 是否删除旧属性(默认 `true`)\n * @returns 处理后的树形结构数组\n *\n * @group Array\n * @example\n * const tree = [\n * { id: 1, name: 'Node 1', children: [...] }\n * ];\n * const renamedTree = renameTreeNodes(tree, { name: 'label' });\n * // 输出:节点中的 `name` 被替换为 `label`,且旧属性被删除\n */\nexport function renameTreeNodes(\n tree: any[],\n renameMap: Record<string, string>,\n childKey: string = 'children',\n deleteOldKeys: boolean = true,\n): any[] {\n return tree.map((node) => {\n const newNode = { ...node }\n\n // 重命名属性\n Object.entries(renameMap).forEach(([oldKey, newKey]) => {\n if (hasOwnProp(newNode, oldKey)) {\n newNode[newKey] = newNode[oldKey]\n if (deleteOldKeys) {\n delete newNode[oldKey]\n }\n }\n })\n\n // 递归处理子节点\n if (Array.isArray(newNode[childKey])) {\n newNode[childKey] = renameTreeNodes(\n newNode[childKey],\n renameMap,\n childKey,\n deleteOldKeys,\n )\n }\n\n return newNode\n })\n}\n\n/**\n * 递归转换树形结构的节点,支持重命名、新增、过滤属性。\n *\n * @param tree - 需要处理的树形数据(根节点数组)\n * @param transformer - 转换函数,接收当前节点和子节点,返回处理后的节点\n * @param childKey - 子节点的键名(默认为 `'children'`)\n * @returns 转换后的树形结构数组\n *\n * @group Array\n * @example\n * // 重命名 `name` 为 `label`,并添加 `isLeaf` 属性\n * const transformedTree = transformTree(tree, (node, children) => ({\n * id: node.id,\n * label: node.name,\n * isLeaf: children.length === 0,\n * children,\n * }));\n */\nexport function transformTree(\n tree: any[],\n transformer: (node: any, children: any[]) => any,\n childKey: string = 'children',\n): any[] {\n return tree.map((node) => {\n const children = node[childKey] ? transformTree(node[childKey], transformer, childKey) : []\n return transformer(node, children)\n })\n}\n\ntype KeysMatching<T, V> = {\n [K in keyof T]-?: T[K] extends V ? K : never\n}[keyof T]\n/**\n * 数组转为对象\n * @param arr - 原始数组\n * @param key - 数组对象键\n * @returns 对应键的对象\n * @group Array\n * @example\n * ```ts\n * const arr = [{ key: 'tom', name: '汤姆' }, { key: 'jack', name: '杰克' }]\n * arrayToObject(arr) // { tom: { key: 'tom', name: '汤姆' }, jack: { key: 'jack', name: '杰克' } }\n *\n * // key 值为空\n * const arr = [{ key: 'tom', name: '汤姆' }, { key: '', name: '杰克' }]\n * arrayToObject(arr) // { tom: { key: 'tom', name: '汤姆' } }\n * ```\n */\nexport function arrayToObject<T>(\n arr: T[],\n key: KeysMatching<T, string | number>,\n): Record<string, T> {\n const result: Record<string, T> = {}\n for (const item of arr) {\n const K = item[key] // K 在这里被 TS 推断为 string | number\n if (!K)\n continue\n result[K as string] = item\n }\n return result\n}\n","import type { Dayjs, ManipulateType, OpUnitType, QUnitType } from 'dayjs'\n/**\n * @module 日期时间\n * @description 提供各种日期时间处理函数,包括日期格式化、日期计算、比较等实用功能。基于 dayjs 库实现。\n */\nimport dayjs from 'dayjs'\nimport isBetween from 'dayjs/plugin/isBetween'\nimport isSameOrAfter from 'dayjs/plugin/isSameOrAfter'\nimport isSameOrBefore from 'dayjs/plugin/isSameOrBefore'\nimport relativeTime from 'dayjs/plugin/relativeTime'\nimport { isNaN, isNumber } from '../is'\n\n// 导入本地化语言\nimport 'dayjs/locale/zh-cn'\n\n// 设置全局语言为中文\ndayjs.locale('zh-cn')\n\n/**\n * 表示日期的各种类型,可以是日期对象、日期字符串或时间戳\n */\nexport type DateLike = Date | string | number\n\n// 注册插件\ndayjs.extend(relativeTime)\ndayjs.extend(isSameOrBefore)\ndayjs.extend(isSameOrAfter)\ndayjs.extend(isBetween)\n\n// 可以按需导入更多插件\n// import weekOfYear from 'dayjs/plugin/weekOfYear'\n// import isLeapYear from 'dayjs/plugin/isLeapYear'\n// import customParseFormat from 'dayjs/plugin/customParseFormat'\n// dayjs.extend(weekOfYear)\n// dayjs.extend(isLeapYear)\n// dayjs.extend(customParseFormat)\n\n/**\n * 创建 dayjs 对象\n * @param date 日期参数,可以是日期对象、时间戳或日期字符串\n * @returns dayjs 对象\n * @group Date\n * @example\n * ```ts\n * createDate() // 当前日期时间\n * createDate('2023-05-15') // 指定日期\n * createDate(1684123456000) // 时间戳\n * ```\n */\nexport function createDate(date?: DateLike | Dayjs): Dayjs {\n return dayjs(date)\n}\n\n/**\n * 判断时间戳是否为毫秒级时间戳\n * @param value 要检查的值\n * @returns 如果是毫秒级时间戳则返回 true,否则返回 false\n * @group Date\n * @example\n * ```ts\n * isMillisecondTimestamp(1673740800000) // true,13位数字\n * isMillisecondTimestamp(1673740800) // false,10位数字,秒级时间戳\n * isMillisecondTimestamp('1673740800000') // false, 字符串不是时间戳\n * isMillisecondTimestamp(new Date()) // false,日期对象不是时间戳\n * ```\n */\nexport function isMillisecondTimestamp(value: unknown): boolean {\n if (!isNumber(value) || value.toString().length !== 13)\n return false\n\n const date = new Date(value)\n return !isNaN(date.getTime())\n}\n\n/**\n * 转换为 dayjs 可接收的参数格式\n * @param value 日期参数,可以是日期对象、时间戳(秒或毫秒)或日期字符串\n * @returns 转换后的参数,如果是秒级时间戳则转为毫秒级,其他类型保持不变\n * @group Date\n * @example\n * ```ts\n * convertToDayjsParam(1673740800) // 1673740800000,秒转为毫秒\n * convertToDayjsParam(1673740800000) // 1673740800000,毫秒保持不变\n * convertToDayjsParam(new Date()) // Date对象,保持不变\n * convertToDayjsParam('2023-01-15') // '2023-01-15',字符串保持不变\n * ```\n */\nexport function convertToDayjsParam(value: DateLike) {\n // 如果是数字,且是10位数字,则可能是秒级时间戳,需要转为毫秒\n if (isNumber(value) && String(value).length === 10) {\n return value * 1000\n }\n return value\n}\n\n/**\n * 格式化日期为指定格式的字符串\n * @param date 日期对象、时间戳或日期字符串\n * @param format 格式字符串,支持的占位符请参考 [dayjs 文档](https://day.js.org/docs/zh-CN/durations/format#%E6%94%AF%E6%8C%81%E7%9A%84%E6%A0%BC%E5%BC%8F%E5%8C%96%E5%8D%A0%E4%BD%8D%E7%AC%A6%E5%88%97%E8%A1%A8)\n * @returns 格式化后的日期字符串\n * @group Date\n * @example\n * ```ts\n * formatDate(new Date(), 'YYYY-MM-DD HH:mm:ss') // \"2023-05-16 14:30:45\"\n * formatDate('2023-05-15', 'YYYY年MM月DD日') // \"2023年05月15日\"\n * formatDate(1684123456000, 'MM/DD/YYYY') // \"05/15/2023\"\n * ```\n */\nexport function formatDate(date: DateLike, format = 'YYYY-MM-DD'): string {\n return dayjs(convertToDayjsParam(date)).format(format)\n}\n\n/**\n * 将日期格式化为完整的时间字符串(YYYY-MM-DD HH:mm:ss)\n * @param date 日期对象、时间戳或日期字符串\n * @returns 格式为 YYYY-MM-DD HH:mm:ss 的日期时间字符串\n * @group Date\n * @example\n * ```ts\n * formatFullTime(new Date()) // \"2023-05-16 14:30:45\"\n * formatFullTime('2023-05-15') // \"2023-05-15 00:00:00\"\n * formatFullTime(1684123456) // \"2023-05-15 10:30:56\"(秒级时间戳会被自动转换)\n * ```\n */\nexport function formatFullTime(date: DateLike) {\n return formatDate(date, 'YYYY-MM-DD HH:mm:ss')\n}\n\n/**\n * 获取当前日期时间的时间戳\n * @returns 当前时间戳(毫秒)\n * @group Date\n * @example\n * ```ts\n * now() // 例如: 1684123456789\n * ```\n */\nexport function now(): number {\n return Date.now()\n}\n\n/**\n * 解析日期字符串为日期对象\n * @param dateStr 日期字符串\n * @returns 日期对象\n * @throws 如果日期格式无效,抛出 TypeError\n * @group Date\n * @example\n * ```ts\n * parseDate('2023-05-15') // Date 对象: Mon May 15 2023 00:00:00\n * parseDate('2023/05/15 14:30:45') // Date 对象: Mon May 15 2023 14:30:45\n * parseDate('invalid date') // 抛出 TypeError: 无效的日期格式\n * ```\n */\nexport function parseDate(dateStr: string): Date {\n const d = dayjs(dateStr)\n if (!d.isValid())\n throw new TypeError('无效的日期格式')\n return d.toDate()\n}\n\n/**\n * 计算两个日期之间的差异\n * @param date1 第一个日期\n * @param date2 第二个日期\n * @param unit 计量单位,默认为 'day',可以是 'year', 'month', 'week', 'day', 'hour', 'minute', 'second', 'millisecond'\n * @returns 两个日期之间的差值,正数表示 date1 晚于 date2,负数表示 date1 早于 date2\n * @group Date\n * @example\n * ```ts\n * diff('2023-05-15', '2023-05-10') // 5(相差5天)\n * diff('2023-05-15', '2023-06-15', 'month') // -1(相差1个月,且第一个日期早于第二个)\n * diff('2023-05-15 08:00', '2023-05-15 06:00', 'hour') // 2(相差2小时)\n * ```\n */\nexport function diff(date1: DateLike, date2: DateLike, unit: QUnitType | OpUnitType = 'day'): number {\n return dayjs(convertToDayjsParam(date1)).diff(dayjs(convertToDayjsParam(date2)), unit)\n}\n\n/**\n * 向日期添加指定时间\n * @param date 原始日期\n * @param amount 要添加的数量,可以为负数\n * @param unit 时间单位,默认为 'day',可以是 'year', 'month', 'week', 'day', 'hour', 'minute', 'second', 'millisecond'\n * @returns 添加后的新日期对象\n * @group Date\n * @example\n * ```ts\n * add(new Date('2023-05-15'), 2, 'day') // Date 对象: Wed May 17 2023\n * add('2023-05-15', -1, 'month') // Date 对象: Sat Apr 15 2023\n * add('2023-05-15 12:00', 30, 'minute') // Date 对象: Mon May 15 2023 12:30:00\n * ```\n */\nexport function add(date: DateLike, amount: number, unit: ManipulateType = 'day'): Date {\n return dayjs(convertToDayjsParam(date)).add(amount, unit).toDate()\n}\n\n/**\n * 向日期添加指定天数\n * @param date 原始日期\n * @param days 要添加的天数(可以为负数)\n * @returns 添加天数后的新日期对象\n * @group Date\n * @example\n * ```ts\n * addDays(new Date('2023-05-15'), 5) // Date 对象: Sat May 20 2023\n * addDays('2023-05-15', -3) // Date 对象: Fri May 12 2023\n * ```\n */\nexport function addDays(date: DateLike, days: number): Date {\n return add(convertToDayjsParam(date), days, 'day')\n}\n\n/**\n * 向日期添加指定月数\n * @param date 原始日期\n * @param months 要添加的月数(可以为负数)\n * @returns 添加月数后的新日期对象\n * @group Date\n * @example\n * ```ts\n * addMonths(new Date('2023-05-15'), 2) // Date 对象: Sat Jul 15 2023\n * addMonths('2023-05-31', 1) // Date 对象: Fri Jun 30 2023(注意月份天数自动调整)\n * addMonths('2023-01-15', -3) // Date 对象: Wed Oct 15 2022\n * ```\n */\nexport function addMonths(date: DateLike, months: number): Date {\n return add(convertToDayjsParam(date), months, 'month')\n}\n\n/**\n * 向日期添加指定年数\n * @param date 原始日期\n * @param years 要添加的年数(可以为负数)\n * @returns 添加年数后的新日期对象\n * @group Date\n * @example\n * ```ts\n * addYears(new Date('2023-05-15'), 1) // Date 对象: Wed May 15 2024\n * addYears('2023-05-15', -3) // Date 对象: Fri May 15 2020\n * addYears('2024-02-29', 1) // Date 对象: Fri Feb 28 2025(注意闰年自动调整)\n * ```\n */\nexport function addYears(date: DateLike, years: number): Date {\n return add(convertToDayjsParam(date), years, 'year')\n}\n\n/**\n * 获取指定日期是一周中的第几天\n * @param date 日期\n * @param startOnMonday 是否从周一开始计算(默认为 false,即从周日开始)\n * @returns 一周中的第几天(0-6),周日为 0,周六为 6;如果 startOnMonday 为 true,则周一为 0,周日为 6\n * @group Date\n * @example\n * ```ts\n * getDayOfWeek(new Date('2023-05-15')) // 1(周一,从周日开始算是第1天)\n * getDayOfWeek('2023-05-15', true) // 0(周一,从周一开始算是第0天)\n * getDayOfWeek('2023-05-14') // 0(周日,从周日开始算是第0天)\n * getDayOfWeek('2023-05-14', true) // 6(周日,从周一开始算是第6天)\n * ```\n */\nexport function getDayOfWeek(date: DateLike, startOnMonday = false): number {\n const d = dayjs(convertToDayjsParam(date))\n const day = d.day()\n if (startOnMonday) {\n return day === 0 ? 6 : day - 1\n }\n return day\n}\n\n/**\n * 检查日期是否在指定范围内\n * @param date 要检查的日期\n * @param startDate 范围起始日期\n * @param endDate 范围结束日期\n * @returns 如果日期在指定范围内(不包括边界)则返回 true,否则返回 false\n * @group Date\n * @example\n * ```ts\n * isDateInRange('2023-05-15', '2023-05-10', '2023-05-20') // true\n * isDateInRange('2023-05-15', '2023-05-15', '2023-05-20') // false(不包括开始日期)\n * isDateInRange('2023-05-15', '2023-05-10', '2023-05-15') // false(不包括结束日期)\n * ```\n */\nexport function isDateInRange(date: DateLike, startDate: DateLike, endDate: DateLike): boolean {\n const d = dayjs(convertToDayjsParam(date))\n return d.isAfter(dayjs(convertToDayjsParam(startDate))) && d.isBefore(dayjs(convertToDayjsParam(endDate)))\n}\n\n/**\n * 获取指定月份的天数\n * @param year 年份\n * @param month 月份(0-11),0 表示一月,11 表示十二月\n * @returns 该月的天数\n * @group Date\n * @example\n * ```ts\n * getDaysInMonth(2023, 1) // 28(2023年2月有28天)\n * getDaysInMonth(2024, 1) // 29(2024年2月有29天,闰年)\n * getDaysInMonth(2023, 0) // 31(2023年1月有31天)\n * ```\n */\nexport function getDaysInMonth(year: number, month: number): number {\n return dayjs(new Date(year, month, 1)).daysInMonth()\n}\n\n/**\n * 获取相对时间描述\n * @param date 日期\n * @param baseDate 基准日期,默认为当前时间\n * @returns 相对时间描述,如\"几分钟前\"、\"几天后\"等\n * @group Date\n * @example\n * ```ts\n * fromNow(new Date(Date.now() - 5 * 60 * 1000)) // \"5分钟前\"\n * fromNow(new Date(Date.now() + 24 * 60 * 60 * 1000)) // \"1天内\"\n * fromNow('2023-01-01', '2023-01-05') // \"4天前\"\n * ```\n */\nexport function fromNow(date: DateLike, baseDate?: DateLike): string {\n date = convertToDayjsParam(date)\n baseDate = baseDate && convertToDayjsParam(baseDate)\n if (baseDate)\n return dayjs(date).from(dayjs(baseDate))\n return dayjs(date).fromNow()\n}\n\n/**\n * 获取日期的开始时间\n * @param date 日期\n * @param unit 单位,可以是 'year', 'month', 'week', 'day', 'hour', 'minute', 'second'\n * @returns 单位开始时间的日期对象\n * @group Date\n * @example\n * ```ts\n * startOf(new Date('2023-05-15 15:30:45'), 'day') // Date 对象: Mon May 15 2023 00:00:00\n * startOf('2023-05-15 15:30:45', 'month') // Date 对象: Mon May 01 2023 00:00:00\n * startOf('2023-05-15 15:30:45', 'hour') // Date 对象: Mon May 15 2023 15:00:00\n * ```\n */\nexport function startOf(date: DateLike, unit: OpUnitType): Date {\n return dayjs(convertToDayjsParam(date)).startOf(unit).toDate()\n}\n\n/**\n * 获取日期的结束时间\n * @param date 日期\n * @param unit 单位,可以是 'year', 'month', 'week', 'day', 'hour', 'minute', 'second'\n * @returns 单位结束时间的日期对象\n * @group Date\n * @example\n * ```ts\n * endOf(new Date('2023-05-15 15:30:45'), 'day') // Date 对象: Mon May 15 2023 23:59:59.999\n * endOf('2023-05-15 15:30:45', 'month') // Date 对象: Wed May 31 2023 23:59:59.999\n * endOf('2023-05-15 15:30:45', 'hour') // Date 对象: Mon May 15 2023 15:59:59.999\n * ```\n */\nexport function endOf(date: DateLike, unit: OpUnitType): Date {\n return dayjs(convertToDayjsParam(date)).endOf(unit).toDate()\n}\n\n/**\n * 格式化日期为人类友好的格式\n * @param date 日期\n * @returns 人类友好的日期描述,如\"今天 HH:mm\"、\"昨天 HH:mm\"、\"明天 HH:mm\"或\"YYYY-MM-DD HH:mm\"\n * @group Date\n * @example\n * ```ts\n * formatHumanReadable(new Date()) // \"今天 15:30\"\n * formatHumanReadable(new Date(Date.now() - 24 * 60 * 60 * 1000)) // \"昨天 15:30\"\n * formatHumanReadable(new Date(Date.now() + 24 * 60 * 60 * 1000)) // \"明天 15:30\"\n * formatHumanReadable('2023-01-01') // \"2023-01-01 00:00\"\n * ```\n */\nexport function formatHumanReadable(date: DateLike): string {\n const d = dayjs(convertToDayjsParam(date))\n const now = dayjs()\n\n if (d.isSame(now, 'day'))\n return `今天 ${d.format('HH:mm')}`\n if (d.isSame(now.subtract(1, 'day'), 'day'))\n return `昨天 ${d.format('HH:mm')}`\n if (d.isSame(now.add(1, 'day'), 'day'))\n return `明天 ${d.format('HH:mm')}`\n if (d.isSame(now, 'year'))\n return d.format('M月D日 HH:mm')\n return d.format('YYYY年M月D日 HH:mm')\n}\n","/**\n * @module 数字处理\n * @description 提供各种数字处理函数,包括数字格式化、计算、范围控制等实用功能\n */\n\n/**\n * 将数字四舍五入到指定小数位\n * @param num 要处理的数字\n * @param precision 小数位数,默认为0(整数)\n * @returns 四舍五入后的数字\n * @group Number\n * @example\n * ```ts\n * round(3.1415) // 3\n * round(3.1415, 2) // 3.14\n * round(3.1415, 3) // 3.142\n * round(3.9999) // 4\n * ```\n */\nexport function round(num: number, precision = 0): number {\n const factor = 10 ** precision\n return Math.round(num * factor) / factor\n}\n\n/**\n * 将数字格式化为带千位分隔符的字符串\n * @param num 要格式化的数字\n * @param locale 区域设置,默认为浏览器默认区域\n * @returns 格式化后的字符串\n * @group Number\n * @example\n * ```ts\n * formatThousands(1234567) // '1,234,567'(根据浏览器默认区域可能有所不同)\n * formatThousands(1234567.89, 'en-US') // '1,234,567.89'\n * formatThousands(1234567.89, 'de-DE') // '1.234.567,89'\n * ```\n */\nexport function formatThousands(num: number, locale?: string): string {\n return num.toLocaleString(locale)\n}\n\n/**\n * 将数字格式化为货币字符串\n * @param value 要格式化的数字\n * @param options 格式化选项\n * @param options.currency 货币代码(如 'CNY', 'USD'),默认为 'CNY'\n * @param options.locale 地区设置(如 'zh-CN', 'en-US'),默认为 'zh-CN'\n * @param options.minimumFractionDigits 最小小数位数,默认为 2\n * @param options.maximumFractionDigits 最大小数位数,默认为 2\n * @returns 格式化后的货币字符串\n * @group Number\n * @example\n * ```ts\n * formatCurrency(1234.56) // '¥1,234.56'\n * formatCurrency(1234.56, { currency: 'USD', locale: 'en-US' }) // '$1,234.56'\n * formatCurrency(1234.56789, { maximumFractionDigits: 4 }) // '¥1,234.5679'\n * formatCurrency(1234, { minimumFractionDigits: 0 }) // '¥1,234'\n * ```\n */\nexport function formatCurrency(\n value: number,\n options: {\n currency?: string\n locale?: string\n minimumFractionDigits?: number\n maximumFractionDigits?: number\n } = {},\n): string {\n const {\n currency = 'CNY',\n locale = 'zh-CN',\n minimumFractionDigits = 2,\n maximumFractionDigits = 2,\n } = options\n\n return new Intl.NumberFormat(locale, {\n style: 'currency',\n currency,\n minimumFractionDigits,\n maximumFractionDigits,\n }).format(value)\n}\n\n/**\n * 确保数字在指定范围内\n * @param num 要限制范围的数字\n * @param min 最小值\n * @param max 最大值\n * @returns 在指定范围内的数字:如果小于最小值返回最小值,如果大于最大值返回最大值\n * @group Number\n * @example\n * ```ts\n * clamp(5, 0, 10) // 5 - 在范围内,保持不变\n * clamp(-5, 0, 10) // 0 - 小于最小值,返回最小值\n * clamp(15, 0, 10) // 10 - 大于最大值,返回最大值\n * ```\n */\nexport function clamp(num: number, min: number, max: number): number {\n return Math.min(Math.max(num, min), max)\n}\n\n/**\n * 生成指定范围内的随机整数(包含边界值)\n * @param min 最小值(包含)\n * @param max 最大值(包含)\n * @returns 指定范围内的随机整数\n * @group Number\n * @example\n * ```ts\n * randomInt(1, 10) // 返回 1 到 10 之间的随机整数,包括 1 和 10\n * randomInt(0, 1) // 返回 0 或 1\n * randomInt(5, 5) // 总是返回 5\n * ```\n */\nexport function randomInt(min: number, max: number): number {\n min = Math.ceil(min)\n max = Math.floor(max)\n return Math.floor(Math.random() * (max - min + 1)) + min\n}\n\n/**\n * 检查一个数字是否为偶数\n * @param num 要检查的数字\n * @returns 如果是偶数则返回 true,否则返回 false\n * @group Number\n * @example\n * ```ts\n * isEven(2) // true\n * isEven(3) // false\n * isEven(0) // true\n * isEven(-4) // true\n * ```\n */\nexport function isEven(num: number): boolean {\n return num % 2 === 0\n}\n\n/**\n * 检查一个数字是否为奇数\n * @param num 要检查的数字\n * @returns 如果是奇数则返回 true,否则返回 false\n * @group Number\n * @example\n * ```ts\n * isOdd(3) // true\n * isOdd(2) // false\n * isOdd(0) // false\n * isOdd(-3) // true\n * ```\n */\nexport function isOdd(num: number): boolean {\n return !isEven(num)\n}\n\n/**\n * 计算百分比值\n * @param value 当前值\n * @param total 总值\n * @param precision 结果保留的小数位数,默认为2\n * @returns 百分比值,如果总值为零则返回 0\n * @group Number\n * @example\n * ```ts\n * percentage(25, 100) // 25\n * percentage(1, 3) // 33.33\n * percentage(1, 3, 0) // 33\n * percentage(5, 0) // 0,避免除以零错误\n * ```\n */\nexport function percentage(value: number, total: number, precision = 2): number {\n if (total === 0)\n return 0\n return round((value / total) * 100, precision)\n}\n\n/**\n * 将数值转换为带\"万\"单位的字符串\n * @param num 要转换的数值\n * @param fractionDigits 小数位数,默认为2\n * @returns 转换后的字符串,如果值大于等于10000则转为\"万\"单位\n * @group Number\n * @example\n * ```ts\n * formatNumberWithTenThousand(1234) // '1234'\n * formatNumberWithTenThousand(12345) // '1.23万'\n * formatNumberWithTenThousand(12345, 1) // '1.2万'\n * formatNumberWithTenThousand(0) // '0'\n * ```\n */\nexport function formatNumberWithTenThousand(num: number, fractionDigits = 2): string {\n if (!num) {\n return '0'\n }\n if (num >= 10000) {\n // 保留两位小数\n return `${(num / 10000).toFixed(fractionDigits)}万`\n }\n else {\n return num.toString()\n }\n}\n","/**\n * 延迟指定的毫秒数\n *\n * @param {number} ms - 需要延迟的毫秒数\n * @returns {Promise<void>} 返回一个在指定时间后resolve的Promise\n * @group Promise\n * @example\n * ```ts\n * // 延迟2秒\n * await delay(2000)\n * console.log('2秒后执行')\n *\n * // 在异步函数中使用\n * async function fetchWithDelay() {\n * await delay(1000)\n * return fetch('/api/data')\n * }\n * ```\n */\nexport function delay(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms))\n}\n","/**\n * @module 字符串处理\n * @description 提供各种字符串处理函数,包括字符串转换、格式化、验证等实用功能\n */\n\nimport { isNaN } from '../is'\n\n/**\n * 将字符串首字母转为大写\n * @param str 输入字符串\n * @returns 首字母大写后的字符串\n * @group String\n * @example\n * ```ts\n * capitalize('hello') // 'Hello'\n * capitalize('') // ''\n * capitalize('a') // 'A'\n * ```\n */\nexport function capitalize(str: string): string {\n if (str.length === 0)\n return str\n return str.charAt(0).toUpperCase() + str.slice(1)\n}\n\n/**\n * 将驼峰命名转换为短横线命名(kebab-case)\n * @param str 驼峰命名的字符串\n * @returns 短横线命名的字符串\n * @group String\n * @example\n * ```ts\n * camelToKebab('helloWorld') // 'hello-world'\n * camelToKebab('HelloWorld') // 'hello-world'\n * camelToKebab('APIVersion') // 'api-version'\n * camelToKebab('iOS9App') // 'i-os9-app'\n * ```\n */\nexport function camelToKebab(str: string): string {\n // 处理首字母大写的情况,如 APIVersion -> api-version\n return str\n .replace(/([A-Z])([A-Z]+)([A-Z])/g, '$1$2-$3') // 处理连续大写字母\n .replace(/([a-z0-9])([A-Z])/g, '$1-$2')\n .toLowerCase()\n}\n\n/**\n * 将短横线命名(kebab-case)转换为驼峰命名(camelCase)\n * @param str 短横线命名的字符串\n * @returns 驼峰命名的字符串\n * @group String\n * @example\n * ```ts\n * kebabToCamel('hello-world') // 'helloWorld'\n * kebabToCamel('api-version') // 'apiVersion'\n * kebabToCamel('i-os9-app') // 'iOs9App'\n * kebabToCamel('--hello') // 'hello'\n * ```\n */\nexport function kebabToCamel(str: string): string {\n return str.replace(/-([a-z])/g, (_, char) => char.toUpperCase())\n}\n\n/**\n * 截取字符串并添加省略号\n * @param str 原始字符串\n * @param length 截取的最大长度,默认为 50\n * @param ellipsis 省略号字符,默认为'...'\n * @returns 截取后的字符串,如果原字符串长度小于等于截取长度,则返回原字符串\n * @group String\n * @example\n * ```ts\n * truncate('这是一个很长的字符串', 5) // '这是...'\n * truncate('这是一个很长的字符串', 5, '…') // '这是一…'\n * truncate('短字符', 10) // '短字符'\n * ```\n */\nexport function truncate(str: string, length: number = 50, ellipsis: string = '...'): string {\n if (str.length <= length)\n return str\n\n // 计算需要保留的字符数 = 总长度 - 省略号长度\n const truncatedLength = length - ellipsis.length\n return str.substring(0, truncatedLength) + ellipsis\n}\n\n/**\n * 生成指定长度的随机字符串\n * @param length 字符串长度\n * @param chars 可选的字符集,默认包含大小写字母和数字\n * @returns 生成的随机字符串\n * @group String\n * @example\n * ```ts\n * randomString(5) // 例如: 'aB9cD'\n * randomString(10) // 例如: 'aBcD1eF2gH'\n * randomString(3, '123456') // 例如: '426'\n * ```\n */\nexport function randomString(length: number, chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'): string {\n let result = ''\n const charsLength = chars.length\n\n for (let i = 0; i < length; i++) {\n result += chars.charAt(Math.floor(Math.random() * charsLength))\n }\n\n return result\n}\n\n/**\n * 将字符串中的 HTML 特殊字符转义,防止 XSS 攻击\n * @param html 包含 HTML 的字符串\n * @returns 转义后的安全字符串\n * @group String\n * @example\n * ```ts\n * escapeHtml('<div>Hello & World</div>') // '&lt;div&gt;Hello &amp; World&lt;/div&gt;'\n * escapeHtml('<script>alert(\"XSS\")</script>') // '&lt;script&gt;alert(&quot;XSS&quot;)&lt;/script&gt;'\n * ```\n */\nexport function escapeHtml(html: string): string {\n const entityMap: Record<string, string> = {\n '&': '&amp;',\n '<': '&lt;',\n '>': '&gt;',\n '\"': '&quot;',\n '\\'': '&#39;',\n '/': '&#x2F;',\n '`': '&#x60;',\n '=': '&#x3D;',\n }\n\n return html.replace(/[&<>\"'`=/]/g, s => entityMap[s] || s)\n}\n\n/**\n * 检查字符串是否为有效的 URL\n * @param url 要检查的 URL 字符串\n * @returns 如果是有效的 URL 则返回 true,否则返回 false\n * @group String\n * @example\n * ```ts\n * isValidUrl('https://example.com') // true\n * isValidUrl('http://localhost:3000') // true\n * isValidUrl('example.com') // false,缺少协议\n * isValidUrl('not a url') // false\n * ```\n */\nexport function isValidUrl(url: string): boolean {\n try {\n return Boolean(new URL(url))\n }\n catch {\n return false\n }\n}\n\n/**\n * 检查字符串是否为有效的电子邮件地址\n * @param email 要检查的电子邮件地址\n * @returns 如果是有效的电子邮件地址则返回 true,否则返回 false\n * @group String\n * @example\n * ```ts\n * @group String\n * isValidEmail('user@example.com') // true\n * @group String\n * isValidEmail('user.name+tag@example.co.uk') // true\n * isValidEmail('invalid@email') // false,缺少顶级域名\n * isValidEmail('not an email') // false\n * ```\n */\nexport function isValidEmail(email: string): boolean {\n const re = /^[\\w.%+-]+@[a-z0-9.-]+\\.[a-z]{2,}$/i\n return re.test(email)\n}\n\n/**\n * 检查字符串是否为空或只包含空白字符\n * @param str 要检查的字符串\n * @returns 如果字符串为空或只包含空白字符,则返回 true\n * @group String\n * @example\n * ```ts\n * isEmptyString('') // true\n * isEmptyString(' \\t\\n ') // true\n * isEmptyString('hello') // false\n * isEmptyString(' hello ') // false\n * ```\n */\nexport function isEmptyString(str: string): boolean {\n return str.trim().length === 0\n}\n\n/**\n * 确保值具有 rpx 单位,主要用于小程序/uni-app 样式处理\n * @param val 需要转化的值,可以是数字或字符串\n * @returns 转化后带有 rpx 单位的字符串,如果输入不是数字则原样返回\n * @group String\n * @example\n * ```ts\n * ensureRpxUnit(100) // '100rpx'\n * ensureRpxUnit('100') // '100rpx'\n * ensureRpxUnit('100px') // '100px',不是数字,保持原样\n * ensureRpxUnit('auto') // 'auto',不是数字,保持原样\n * ```\n */\nexport function ensureRpxUnit(val: string | number): string {\n const str = Number(val)\n if (isNaN(str)) {\n return val as string\n }\n return `${val}rpx`\n}\n\n/**\n * 替换表格数据中指定字段的 &nbsp; 为不换行空格\n *\n * @param {Array<Record<string, any>>} tableData - 表格数据数组或Vue ref\n * @param {string} key - 需要处理的字段名\n * @returns {Array<Record<string, any>>} 处理后的表格数据数组\n *\n * @group String\n * @example\n * ```ts\n * // 基本用法\n * const data = [\n * { name: 'John&nbsp;Doe', age: 30 },\n * { name: 'Jane&nbsp;&nbsp;Smith', age: 25 }\n * ]\n * const result = replaceNBSP(data, 'name')\n * // 结果: [\n * // { name: 'John Doe', age: 30 },\n * // { name: 'Jane Smith', age: 25 }\n * // ]\n *\n * // 使用ref包装的数据 (在Vue中使用)\n * const refData = ref([\n * { desc: 'Product&nbsp;Info', price: 99 },\n * { desc: 'Service&nbsp;&nbsp;Details', price: 50 }\n * ])\n * const result = replaceNBSP(refData, 'desc')\n * // 结果: [\n * // { desc: 'Product Info', price: 99 },\n * // { desc: 'Service Details', price: 50 }\n * // ]\n *\n * // 空数组情况\n * const emptyData = []\n * const result = replaceNBSP(emptyData, 'name')\n * // 结果: []\n * ```\n */\nexport function replaceNBSP<T extends Record<string, string | number | boolean | object>>(\n tableData: T[] | { value: T[] },\n key: string,\n): T[] {\n // 如果是 ref 对象,获取其 value\n const unwrappedData = Array.isArray(tableData) ? tableData : tableData.value\n\n if (unwrappedData.length) {\n return unwrappedData.map((item) => {\n if (typeof item[key] === 'string') {\n // 创建一个新对象,不修改原对象\n return {\n ...item,\n [key]: (item[key] as string).replace(/&nbsp;/g, '\\u00A0\\u00A0'),\n }\n }\n return item\n })\n }\n\n return []\n}\n","import { objectToQueryString } from '../object'\n\n/**\n * 将对象转换为URL查询字符串\n *\n * @deprecated 请使用 objectToQueryString 函数代替,它在 object 模块中。该函数将在下一个主要版本中移除。\n * @param {Record<string, any>} params - 需要转换的对象\n * @returns {string} 转换后的查询字符串,如果有参数则以?开头\n * @group Url\n * @example\n * ```ts\n * // 基本用法\n * getQueryStringify({ name: 'John', age: 30 })\n * // 返回: ?name=John&age=30\n *\n * // 包含对象的情况\n * getQueryStringify({ user: { name: 'John', age: 30 }, active: true })\n * // 返回: ?user={\"name\":\"John\",\"age\":30}&active=true\n *\n * // 空对象\n * getQueryStringify({})\n * // 返回: ''\n *\n * // null 或 undefined\n * getQueryStringify(null)\n * // 返回: ''\n * ```\n */\nexport function getQueryStringify(params: Record<string, any> | null | undefined): string {\n if (!params)\n return ''\n\n const queryString = objectToQueryString(params)\n\n if (queryString)\n return `?${queryString}`\n\n return ''\n}\n"]}
1
+ {"version":3,"sources":["../packages/is/index.ts","../packages/object/index.ts","../packages/string/index.ts","../packages/array/index.ts","../packages/date/index.ts","../packages/number/index.ts","../packages/promise/index.ts","../packages/url/index.ts"],"names":["isString","val","isNumber","isNaN","isBoolean","isFunction","isObject","isArray","isDate","isRegExp","isPromise","isMap","isSet","isSymbol","isPrimitive","isUndefined","isNull","isNullOrUndefined","isEmptyObject","isEmpty","value","isPlainObject","proto","hasOwnProp","obj","prop","deepClone","item","cloned","key","get","path","defaultValue","keys","result","pick","omit","objectToQueryString","_","merge","objects","deepMerge","sourceValue","targetValue","filterObjectByKeys","originalObject","keysArray","keyMapping","newObject","newKey","capitalize","str","camelToKebab","kebabToCamel","char","truncate","length","ellipsis","truncatedLength","randomString","chars","charsLength","i","escapeHtml","html","entityMap","s","isValidUrl","url","isValidEmail","email","isEmptyString","ensureRpxUnit","replaceNBSP","remove","array","unique","chunk","size","last","first","shuffle","j","sample","index","isEqual","a","b","groupBy","keyFn","appendUniversalOption","options","name","valueKey","renameTreeNodes","tree","renameMap","childKey","deleteOldKeys","node","newNode","oldKey","transformTree","transformer","children","arrayToObject","arr","K","arrayReplaceNBSP","dayjs","relativeTime","isSameOrBefore","isSameOrAfter","isBetween","createDate","date","isMillisecondTimestamp","convertToDayjsParam","formatDate","format","formatFullTime","now","parseDate","dateStr","d","diff","date1","date2","unit","add","amount","addDays","days","addMonths","months","addYears","years","getDayOfWeek","startOnMonday","day","isDateInRange","startDate","endDate","getDaysInMonth","year","month","fromNow","baseDate","startOf","endOf","formatHumanReadable","round","num","precision","factor","formatThousands","locale","formatCurrency","currency","minimumFractionDigits","maximumFractionDigits","clamp","min","max","randomInt","isEven","isOdd","percentage","total","formatNumberWithTenThousand","fractionDigits","delay","ms","resolve","getQueryStringify","params","queryString"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * @module 类型检查\n * @description 提供各种数据类型检查函数,用于判断值的类型、判断对象特性等\n */\n\n/**\n * 检查值是否为字符串类型\n * @param val 要检查的值\n * @returns 如果是字符串则返回 true,否则返回 false\n * @group Is\n * @example\n * ```ts\n * isString('hello') // true\n * isString(123) // false\n * isString(new String('hello')) // false(注意:包装对象不是原始字符串类型)\n * ```\n */\nexport function isString(val: unknown): val is string {\n return typeof val === 'string'\n}\n\n/**\n * 检查值是否为数字类型\n * @param val 要检查的值\n * @returns 如果是数字则返回 true,否则返回 false(NaN 会返回 false)\n * @group Is\n * @example\n * ```ts\n * isNumber(123) // true\n * isNumber(-45.67) // true\n * isNumber('123') // false\n * isNumber(NaN) // false\n * isNumber(Infinity) // true\n * ```\n */\nexport function isNumber(val: unknown): val is number {\n return typeof val === 'number' && !isNaN(val)\n}\n\n/**\n * 检查值是否为布尔类型\n * @param val 要检查的值\n * @returns 如果是布尔值则返回 true,否则返回 false\n * @group Is\n * @example\n * ```ts\n * isBoolean(true) // true\n * isBoolean(false) // true\n * isBoolean(0) // false\n * isBoolean('false') // false\n * isBoolean(new Boolean(true)) // false(包装对象不是原始布尔类型)\n * ```\n */\nexport function isBoolean(val: unknown): val is boolean {\n return typeof val === 'boolean'\n}\n\n/**\n * 检查值是否为函数类型\n * @param val 要检查的值\n * @returns 如果是函数则返回 true,否则返回 false\n * @group Is\n * @example\n * ```ts\n * isFunction(() => {}) // true\n * isFunction(function() {}) // true\n * isFunction(class {}) // true\n * isFunction(Math.sin) // true\n * isFunction({}) // false\n * ```\n */\nexport function isFunction(val: unknown): val is ((...args: any[]) => any) {\n return typeof val === 'function'\n}\n\n/**\n * 检查值是否为对象类型(不包括 null)\n * @param val 要检查的值\n * @returns 如果是对象则返回 true,否则返回 false\n * @group Is\n * @example\n * ```ts\n * isObject({}) // true\n * isObject([]) // true(数组也是对象)\n * isObject(new Date()) // true\n * isObject(null) // false\n * isObject(undefined) // false\n * isObject(123) // false\n * ```\n */\nexport function isObject(val: unknown): val is Record<any, any> {\n return val !== null && typeof val === 'object'\n}\n\n/**\n * 检查值是否为数组类型\n * @param val 要检查的值\n * @returns 如果是数组则返回 true,否则返回 false\n * @group Is\n * @example\n * ```ts\n * isArray([]) // true\n * isArray([1, 2, 3]) // true\n * isArray(new Array()) // true\n * isArray({}) // false\n * isArray('abc') // false\n * ```\n */\nexport function isArray(val: unknown): val is any[] {\n return Array.isArray(val)\n}\n\n/**\n * 检查值是否为日期类型\n * @param val 要检查的值\n * @returns 如果是日期对象则返回 true,否则返回 false\n * @group Is\n * @example\n * ```ts\n * isDate(new Date()) // true\n * isDate(Date.now()) // false(时间戳是数字,不是日期对象)\n * isDate('2023-05-15') // false(日期字符串不是日期对象)\n * ```\n */\nexport function isDate(val: unknown): val is Date {\n return val instanceof Date\n}\n\n/**\n * 检查值是否为正则表达式\n * @param val 要检查的值\n * @returns 如果是正则表达式则返回 true,否则返回 false\n * @group Is\n * @example\n * ```ts\n * isRegExp(/abc/) // true\n * isRegExp(new RegExp('abc')) // true\n * isRegExp('/abc/') // false(字符串不是正则表达式)\n * isRegExp({}) // false\n * ```\n */\nexport function isRegExp(val: unknown): val is RegExp {\n return val instanceof RegExp\n}\n\n/**\n * 检查值是否为 Promise\n * @param val 要检查的值\n * @returns 如果是 Promise 则返回 true,否则返回 false\n * @group Is\n * @example\n * ```ts\n * isPromise(Promise.resolve()) // true\n * isPromise(new Promise(() => {})) // true\n * isPromise({ then: () => {}, catch: () => {} }) // true(类 Promise 对象也会返回 true)\n * isPromise({}) // false\n * isPromise(null) // false\n * ```\n */\nexport function isPromise<T = any>(val: unknown): val is Promise<T> {\n return isObject(val) && isFunction((val as any).then) && isFunction((val as any).catch)\n}\n\n/**\n * 检查值是否为 Map\n * @param val 要检查的值\n * @returns 如果是 Map 则返回 true,否则返回 false\n * @group Is\n * @example\n * ```ts\n * isMap(new Map()) // true\n * isMap(new WeakMap()) // false\n * isMap({}) // false\n * ```\n */\nexport function isMap<K = any, V = any>(val: unknown): val is Map<K, V> {\n return val instanceof Map\n}\n\n/**\n * 检查值是否为 Set\n * @param val 要检查的值\n * @returns 如果是 Set 则返回 true,否则返回 false\n * @group Is\n * @example\n * ```ts\n * isSet(new Set()) // true\n * isSet(new WeakSet()) // false\n * isSet([]) // false\n * ```\n */\nexport function isSet<T = any>(val: unknown): val is Set<T> {\n return val instanceof Set\n}\n\n/**\n * 检查值是否为 Symbol\n * @param val 要检查的值\n * @returns 如果是 Symbol 则返回 true,否则返回 false\n * @group Is\n * @example\n * ```ts\n * isSymbol(Symbol('foo')) // true\n * isSymbol(Symbol.for('bar')) // true\n * isSymbol('symbol') // false\n * ```\n */\nexport function isSymbol(val: unknown): val is symbol {\n return typeof val === 'symbol'\n}\n\n/**\n * 检查值是否为原始类型(string、number、boolean、symbol、bigint、null、undefined)\n * @param val 要检查的值\n * @returns 如果是原始类型则返回 true,否则返回 false\n * @group Is\n * @example\n * ```ts\n * isPrimitive('hello') // true\n * isPrimitive(123) // true\n * isPrimitive(true) // true\n * isPrimitive(Symbol()) // true\n * isPrimitive(null) // true\n * isPrimitive(undefined) // true\n * isPrimitive(BigInt(123)) // true\n * isPrimitive({}) // false\n * isPrimitive([]) // false\n * isPrimitive(() => {}) // false\n * ```\n */\nexport function isPrimitive(val: unknown): boolean {\n return val === null || (typeof val !== 'object' && typeof val !== 'function')\n}\n\n/**\n * 检查值是否为 undefined\n * @param val 要检查的值\n * @returns 如果是 undefined 则返回 true,否则返回 false\n * @group Is\n * @example\n * ```ts\n * isUndefined(undefined) // true\n * isUndefined(void 0) // true\n * isUndefined(null) // false\n * isUndefined('') // false\n * ```\n */\nexport function isUndefined(val: unknown): val is undefined {\n return typeof val === 'undefined'\n}\n\n/**\n * 检查值是否为 null\n * @param val 要检查的值\n * @returns 如果是 null 则返回 true,否则返回 false\n * @group Is\n * @example\n * ```ts\n * isNull(null) // true\n * isNull(undefined) // false\n * isNull(0) // false\n * isNull('') // false\n * ```\n */\nexport function isNull(val: unknown): val is null {\n return val === null\n}\n\n/**\n * 检查值是否为 null 或 undefined\n * @param val 要检查的值\n * @returns 如果是 null 或 undefined 则返回 true,否则返回 false\n * @group Is\n * @example\n * ```ts\n * isNullOrUndefined(null) // true\n * isNullOrUndefined(undefined) // true\n * isNullOrUndefined(void 0) // true\n * isNullOrUndefined('') // false\n * isNullOrUndefined(0) // false\n * ```\n */\nexport function isNullOrUndefined(val: unknown): val is null | undefined {\n return isNull(val) || isUndefined(val)\n}\n\n/**\n * 检查对象是否为空对象(没有自身可枚举属性)\n * @param val 要检查的值\n * @returns 如果是空对象则返回 true,否则返回 false;如果不是对象类型则返回 false\n * @group Is\n * @example\n * ```ts\n * isEmptyObject({}) // true\n * isEmptyObject({ a: 1 }) // false\n * isEmptyObject([]) // true(空数组也会返回 true)\n * isEmptyObject(null) // false(不是对象)\n * isEmptyObject(Object.create(null)) // true\n * isEmptyObject(Object.create({ toString: () => '' })) // true(不包括继承的属性)\n * ```\n */\nexport function isEmptyObject(val: unknown): boolean {\n return isObject(val) && Object.keys(val).length === 0\n}\n\n/**\n * 检查值是否为空(null、undefined、空字符串、空数组或空对象)\n * @param val 要检查的值\n * @returns 如果是空值则返回 true,否则返回 false\n * @group Is\n * @example\n * ```ts\n * isEmpty(null) // true\n * isEmpty(undefined) // true\n * isEmpty('') // true\n * isEmpty(' ') // true(空白字符串也视为空)\n * isEmpty([]) // true\n * isEmpty({}) // true\n * isEmpty(0) // false\n * isEmpty(false) // false\n * isEmpty(' hello ') // false\n * ```\n */\nexport function isEmpty(val: unknown): boolean {\n if (isNullOrUndefined(val))\n return true\n if (isString(val))\n return val.trim().length === 0\n if (isArray(val))\n return val.length === 0\n if (isObject(val))\n return isEmptyObject(val)\n return false\n}\n\n/**\n * 检查值是否为 NaN\n * @param value 要检查的值\n * @returns 如果值是 NaN 则返回 true,否则返回 false\n * @group Is\n * @example\n * ```ts\n * isNaN(NaN) // true\n * isNaN(Number('abc')) // true\n * isNaN(0 / 0) // true\n * isNaN(123) // false\n * isNaN('123') // false(不同于全局 isNaN,此函数不会先尝试转换为数字)\n * ```\n */\nexport function isNaN(value: unknown): boolean {\n return Number.isNaN(value)\n}\n\n/**\n * 检查值是否为普通对象(由 Object 构造函数创建或对象字面量)\n *\n * @param {unknown} value - 要检查的值\n * @returns {boolean} 如果值是普通对象则返回 true,否则返回 false\n *\n * @group Is\n * @example\n * ```ts\n * isPlainObject({}) // true\n * isPlainObject({ a: 1 }) // true\n * isPlainObject(new Date()) // false\n * isPlainObject([]) // false\n * isPlainObject(null) // false\n * ```\n */\nexport function isPlainObject(value: unknown): value is Record<string, any> {\n if (typeof value !== 'object' || value === null) {\n return false\n }\n\n const proto = Object.getPrototypeOf(value)\n return proto === Object.prototype || proto === null\n}\n","/**\n * @module 对象操作\n * @description 提供各种对象处理函数,包括对象深拷贝、合并、转换等实用功能\n */\n\nimport { isPlainObject } from '../is'\n\n/**\n * 检查对象是否具有指定的自有属性。\n *\n * @param {object} obj - 需要检查的对象\n * @param {string | symbol} prop - 需要检查的属性键\n * @returns {boolean} 如果对象具有该自有属性,则返回 true,否则返回 false\n * @group Object\n * @example\n * ```ts\n * const obj = { name: 'Tom', age: 25 }\n * hasOwnProp(obj, 'name') // true\n * hasOwnProp(obj, 'toString') // false,toString 是继承的属性\n * ```\n */\nexport function hasOwnProp(obj: object, prop: string | symbol): boolean {\n return Object.prototype.hasOwnProperty.call(obj, prop)\n}\n\n/**\n * 深拷贝对象,支持基本类型、数组、对象、日期和正则表达式\n * @param obj 要拷贝的对象\n * @returns 深拷贝后的对象,与原对象完全独立\n * @group Object\n * @example\n * ```ts\n * const original = { a: 1, b: { c: 2 }, d: [1, 2, 3], e: new Date() }\n * const copy = deepClone(original)\n * copy.b.c = 100\n * console.log(original.b.c) // 2,原对象不受影响\n *\n * // 支持日期对象\n * const date = new Date()\n * const clonedDate = deepClone(date)\n * console.log(date === clonedDate) // false,不是同一引用\n * ```\n */\nexport function deepClone<T>(obj: T): T {\n if (obj === null || typeof obj !== 'object') {\n return obj\n }\n\n if (obj instanceof Date) {\n return new Date(obj.getTime()) as unknown as T\n }\n\n if (obj instanceof RegExp) {\n return new RegExp(obj.source, obj.flags) as unknown as T\n }\n\n if (Array.isArray(obj)) {\n return obj.map(item => deepClone(item)) as unknown as T\n }\n\n const cloned: Record<string, any> = {}\n Object.keys(obj as Record<string, any>).forEach((key) => {\n cloned[key] = deepClone((obj as Record<string, any>)[key])\n })\n\n return cloned as T\n}\n\n/**\n * 从对象中获取指定路径的值,支持点分隔的嵌套路径\n * @param obj 源对象\n * @param path 属性路径,如 'user.address.street'\n * @param defaultValue 默认值,当路径不存在时返回\n * @returns 路径对应的值,如果路径不存在则返回默认值\n * @group Object\n * @example\n * ```ts\n * const obj = { user: { profile: { name: 'Tom', age: 25 }, roles: ['admin'] } }\n *\n * get(obj, 'user.profile.name') // 'Tom'\n * get(obj, 'user.roles.0') // 'admin'\n * get(obj, 'user.settings', { theme: 'dark' }) // { theme: 'dark' }(路径不存在,返回默认值)\n * get(obj, 'user.profile.gender') // undefined(路径不存在且没提供默认值)\n * get(obj, 'user.profile.gender', 'unknown') // 'unknown'(使用默认值)\n * ```\n */\nexport function get<T = any>(obj: Record<string, any>, path: string, defaultValue?: T): T | undefined {\n const keys = path.split('.')\n let result = obj\n\n for (const key of keys) {\n if (result === undefined || result === null) {\n return defaultValue\n }\n result = result[key]\n }\n\n return (result === undefined) ? defaultValue : result as T\n}\n\n/**\n * 从对象中选择指定的属性,创建一个新对象\n * @param obj 原始对象\n * @param keys 要选择的键数组\n * @returns 包含指定键的新对象\n * @group Object\n * @example\n * ```ts\n * @group Object\n * const user = { id: 1, name: 'Tom', age: 25, email: 'tom@example.com' }\n *\n * @group Object\n * pick(user, ['name', 'email']) // { name: 'Tom', email: 'tom@example.com' }\n * pick(user, ['name', 'gender']) // { name: 'Tom' }(不存在的键会被忽略)\n * pick(user, []) // {}(空数组返回空对象)\n * ```\n */\nexport function pick<T extends Record<string, any>, K extends keyof T>(obj: T, keys: K[]): Pick<T, K> {\n return keys.reduce((result, key) => {\n if (key in obj) {\n result[key] = obj[key]\n }\n return result\n }, {} as Pick<T, K>)\n}\n\n/**\n * 从对象中排除指定的属性,创建一个新对象\n * @param obj 原始对象\n * @param keys 要排除的键数组\n * @returns 不包含指定键的新对象\n * @group Object\n * @example\n * ```ts\n * const user = { id: 1, name: 'Tom', age: 25, password: '123456' }\n *\n * omit(user, ['password']) // { id: 1, name: 'Tom', age: 25 }\n * omit(user, ['id', 'age']) // { name: 'Tom', password: '123456' }\n * omit(user, ['nonExistent']) // 原对象的拷贝,不存在的键会被忽略\n * ```\n */\nexport function omit<T extends Record<string, any>, K extends keyof T>(obj: T, keys: K[]): Omit<T, K> {\n const result = { ...obj }\n keys.forEach((key) => {\n delete result[key]\n })\n return result\n}\n\n/**\n * 将对象转换为 URL 查询字符串\n * @param obj 要转换的对象\n * @returns 格式化后的查询字符串(不包含前导?)\n * @group Object\n * @example\n * ```ts\n * objectToQueryString({ name: 'Tom', age: 25 }) // 'name=Tom&age=25'\n * objectToQueryString({ search: 'hello world', page: 1 }) // 'search=hello%20world&page=1'\n * objectToQueryString({ tags: ['js', 'ts'] }) // 'tags=js&tags=ts'\n * objectToQueryString({ name: 'Tom', empty: null }) // 'name=Tom'(null 和 undefined 会被过滤)\n * ```\n */\nexport function objectToQueryString(obj: Record<string, any>): string {\n return Object.entries(obj)\n .filter(([_, value]) => value !== undefined && value !== null)\n .map(([key, value]) => {\n if (Array.isArray(value)) {\n return value.map(item => `${encodeURIComponent(key)}=${encodeURIComponent(String(item))}`).join('&')\n }\n return `${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`\n })\n .join('&')\n}\n\n/**\n * 合并多个对象,后面的对象的属性会覆盖前面的\n * @param objects 要合并的对象数组\n * @returns 合并后的新对象\n * @group Object\n * @example\n * ```ts\n * merge({ a: 1 }, { b: 2 }) // { a: 1, b: 2 }\n * merge({ a: 1 }, { a: 2, b: 2 }) // { a: 2, b: 2 }(后面对象的属性会覆盖前面的)\n * merge({ a: { x: 1 } }, { a: { y: 2 } }) // { a: { y: 2 } }(不是深度合并)\n * merge({}, { a: 1 }, { b: 2 }, { c: 3 }) // { a: 1, b: 2, c: 3 }\n * ```\n */\nexport function merge<T extends Record<string, any>>(...objects: T[]): T {\n return Object.assign({}, ...objects)\n}\n\n/**\n * 深度合并多个对象,会递归合并嵌套对象\n * @param objects 要合并的对象数组\n * @returns 深度合并后的新对象\n * @group Object\n * @example\n * ```ts\n * deepMerge({ a: { x: 1 } }, { a: { y: 2 } }) // { a: { x: 1, y: 2 } }\n * deepMerge({ a: 1 }, { b: 2 }) // { a: 1, b: 2 }\n * deepMerge({ a: [1, 2] }, { a: [3, 4] }) // { a: [3, 4] }(数组会被替换,不会合并)\n * deepMerge({}, { a: null }, { a: { b: 2 } }) // { a: { b: 2 } }(null 会被后面的对象覆盖)\n * ```\n */\nexport function deepMerge(...objects: Record<string, any>[]): Record<string, any> {\n const result: Record<string, any> = {}\n\n objects.forEach((obj) => {\n if (!isPlainObject(obj))\n return\n\n Object.keys(obj).forEach((key) => {\n const sourceValue = obj[key]\n const targetValue = result[key]\n\n // 如果两个值都是对象,就递归合并\n if (isPlainObject(sourceValue) && isPlainObject(targetValue)) {\n result[key] = deepMerge(targetValue, sourceValue)\n }\n else {\n // 否则直接覆盖\n result[key] = deepClone(sourceValue)\n }\n })\n })\n\n return result\n}\n\n/**\n * 根据传入的键数组和键名映射对象过滤并重命名对象,返回一个新对象\n * @param originalObject 要过滤的原始对象\n * @param keysArray 要保留的键名数组\n * @param keyMapping 可选的键名映射对象,格式为 { 原键名: 新键名 }\n * @returns 返回一个新对象,其中只包含原对象中匹配的键值对,并根据映射重命名键\n * @group Object\n * @example\n * ```ts\n * const originalObject = { name: \"John\", age: 30, gender: \"male\", country: \"USA\" }\n * const keysToFilter = [\"name\", \"country\"]\n * const keyMapping = { name: \"fullName\", country: \"location\" }\n * const result = filterObjectByKeys(originalObject, keysToFilter, keyMapping)\n * // 结果: { fullName: 'John', location: 'USA' }\n * ```\n */\nexport function filterObjectByKeys(\n originalObject: Record<string, any>,\n keysArray: string[],\n keyMapping: Record<string, string> = {},\n): Record<string, any> {\n return keysArray.reduce((newObject: Record<string, any>, key: string) => {\n if (hasOwnProp(originalObject, key)) {\n const newKey = keyMapping[key] || key // 如果有映射,就用新键名,否则用原键名\n newObject[newKey] = originalObject[key]\n }\n return newObject\n }, {})\n}\n","/**\n * @module 字符串处理\n * @description 提供各种字符串处理函数,包括字符串转换、格式化、验证等实用功能\n */\n\nimport { isNaN, isString } from '../is'\n\n/**\n * 将字符串首字母转为大写\n * @param str 输入字符串\n * @returns 首字母大写后的字符串\n * @group String\n * @example\n * ```ts\n * capitalize('hello') // 'Hello'\n * capitalize('') // ''\n * capitalize('a') // 'A'\n * ```\n */\nexport function capitalize(str: string): string {\n if (str.length === 0)\n return str\n return str.charAt(0).toUpperCase() + str.slice(1)\n}\n\n/**\n * 将驼峰命名转换为短横线命名(kebab-case)\n * @param str 驼峰命名的字符串\n * @returns 短横线命名的字符串\n * @group String\n * @example\n * ```ts\n * camelToKebab('helloWorld') // 'hello-world'\n * camelToKebab('HelloWorld') // 'hello-world'\n * camelToKebab('APIVersion') // 'api-version'\n * camelToKebab('iOS9App') // 'i-os9-app'\n * ```\n */\nexport function camelToKebab(str: string): string {\n // 处理首字母大写的情况,如 APIVersion -> api-version\n return str\n .replace(/([A-Z])([A-Z]+)([A-Z])/g, '$1$2-$3') // 处理连续大写字母\n .replace(/([a-z0-9])([A-Z])/g, '$1-$2')\n .toLowerCase()\n}\n\n/**\n * 将短横线命名(kebab-case)转换为驼峰命名(camelCase)\n * @param str 短横线命名的字符串\n * @returns 驼峰命名的字符串\n * @group String\n * @example\n * ```ts\n * kebabToCamel('hello-world') // 'helloWorld'\n * kebabToCamel('api-version') // 'apiVersion'\n * kebabToCamel('i-os9-app') // 'iOs9App'\n * kebabToCamel('--hello') // 'hello'\n * ```\n */\nexport function kebabToCamel(str: string): string {\n return str.replace(/-([a-z])/g, (_, char) => char.toUpperCase())\n}\n\n/**\n * 截取字符串并添加省略号\n * @param str 原始字符串\n * @param length 截取的最大长度,默认为 50\n * @param ellipsis 省略号字符,默认为'...'\n * @returns 截取后的字符串,如果原字符串长度小于等于截取长度,则返回原字符串\n * @group String\n * @example\n * ```ts\n * truncate('这是一个很长的字符串', 5) // '这是...'\n * truncate('这是一个很长的字符串', 5, '…') // '这是一…'\n * truncate('短字符', 10) // '短字符'\n * ```\n */\nexport function truncate(str: string, length: number = 50, ellipsis: string = '...'): string {\n if (str.length <= length)\n return str\n\n // 计算需要保留的字符数 = 总长度 - 省略号长度\n const truncatedLength = length - ellipsis.length\n return str.substring(0, truncatedLength) + ellipsis\n}\n\n/**\n * 生成指定长度的随机字符串\n * @param length 字符串长度\n * @param chars 可选的字符集,默认包含大小写字母和数字\n * @returns 生成的随机字符串\n * @group String\n * @example\n * ```ts\n * randomString(5) // 例如: 'aB9cD'\n * randomString(10) // 例如: 'aBcD1eF2gH'\n * randomString(3, '123456') // 例如: '426'\n * ```\n */\nexport function randomString(length: number, chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'): string {\n let result = ''\n const charsLength = chars.length\n\n for (let i = 0; i < length; i++) {\n result += chars.charAt(Math.floor(Math.random() * charsLength))\n }\n\n return result\n}\n\n/**\n * 将字符串中的 HTML 特殊字符转义,防止 XSS 攻击\n * @param html 包含 HTML 的字符串\n * @returns 转义后的安全字符串\n * @group String\n * @example\n * ```ts\n * escapeHtml('<div>Hello & World</div>') // '&lt;div&gt;Hello &amp; World&lt;/div&gt;'\n * escapeHtml('<script>alert(\"XSS\")</script>') // '&lt;script&gt;alert(&quot;XSS&quot;)&lt;/script&gt;'\n * ```\n */\nexport function escapeHtml(html: string): string {\n const entityMap: Record<string, string> = {\n '&': '&amp;',\n '<': '&lt;',\n '>': '&gt;',\n '\"': '&quot;',\n '\\'': '&#39;',\n '/': '&#x2F;',\n '`': '&#x60;',\n '=': '&#x3D;',\n }\n\n return html.replace(/[&<>\"'`=/]/g, s => entityMap[s] || s)\n}\n\n/**\n * 检查字符串是否为有效的 URL\n * @param url 要检查的 URL 字符串\n * @returns 如果是有效的 URL 则返回 true,否则返回 false\n * @group String\n * @example\n * ```ts\n * isValidUrl('https://example.com') // true\n * isValidUrl('http://localhost:3000') // true\n * isValidUrl('example.com') // false,缺少协议\n * isValidUrl('not a url') // false\n * ```\n */\nexport function isValidUrl(url: string): boolean {\n try {\n return Boolean(new URL(url))\n }\n catch {\n return false\n }\n}\n\n/**\n * 检查字符串是否为有效的电子邮件地址\n * @param email 要检查的电子邮件地址\n * @returns 如果是有效的电子邮件地址则返回 true,否则返回 false\n * @group String\n * @example\n * ```ts\n * @group String\n * isValidEmail('user@example.com') // true\n * @group String\n * isValidEmail('user.name+tag@example.co.uk') // true\n * isValidEmail('invalid@email') // false,缺少顶级域名\n * isValidEmail('not an email') // false\n * ```\n */\nexport function isValidEmail(email: string): boolean {\n const re = /^[\\w.%+-]+@[a-z0-9.-]+\\.[a-z]{2,}$/i\n return re.test(email)\n}\n\n/**\n * 检查字符串是否为空或只包含空白字符\n * @param str 要检查的字符串\n * @returns 如果字符串为空或只包含空白字符,则返回 true\n * @group String\n * @example\n * ```ts\n * isEmptyString('') // true\n * isEmptyString(' \\t\\n ') // true\n * isEmptyString('hello') // false\n * isEmptyString(' hello ') // false\n * ```\n */\nexport function isEmptyString(str: string): boolean {\n return str.trim().length === 0\n}\n\n/**\n * 确保值具有 rpx 单位,主要用于小程序/uni-app 样式处理\n * @param val 需要转化的值,可以是数字或字符串\n * @returns 转化后带有 rpx 单位的字符串,如果输入不是数字则原样返回\n * @group String\n * @example\n * ```ts\n * ensureRpxUnit(100) // '100rpx'\n * ensureRpxUnit('100') // '100rpx'\n * ensureRpxUnit('100px') // '100px',不是数字,保持原样\n * ensureRpxUnit('auto') // 'auto',不是数字,保持原样\n * ```\n */\nexport function ensureRpxUnit(val: string | number): string {\n const str = Number(val)\n if (isNaN(str)) {\n return val as string\n }\n return `${val}rpx`\n}\n\n/**\n * 替换字符串中的 `&nbsp;` 为不换行空格\n *\n * @param {string} str - 字符串\n * @returns {string} 处理后的字符串\n *\n * @group String\n * @example\n * ```ts\n * // 基本用法\n * replaceNBSP('John&nbsp;Doe') // 'John Doe'\n * replaceNBSP('Jane&nbsp;&nbsp;Smith') // 'Jane Smith'\n * replaceNBSP('Smith') // 'Smith'\n * ```\n */\nexport function replaceNBSP(str?: string): string {\n if (!isString(str)) {\n return str as any // 应该忽略非字符串字段\n }\n\n return str.replace(/&nbsp;/g, ' ').replace(/\\u00A0/g, ' ')\n}\n","/**\n * @module 数组操作\n * @description 提供各种数组处理函数,包括数组转换、查询、过滤等实用功能。这些函数都不会修改原始数组,而是返回新的数组或值。\n */\n\nimport { hasOwnProp } from '../object'\nimport { replaceNBSP } from '../string'\n\n/**\n * 从数组中移除指定的项\n * @param array 原始数组\n * @param item 要移除的项\n * @returns 移除指定项后的新数组,不会修改原始数组\n * @group Array\n * @example\n * ```ts\n * const numbers = [1, 2, 3, 4, 5]\n * const newArray = remove(numbers, 3) // [1, 2, 4, 5]\n * console.log(numbers) // 原数组不变: [1, 2, 3, 4, 5]\n *\n * // 移除字符串\n * const fruits = ['苹果', '香蕉', '橙子']\n * const newFruits = remove(fruits, '香蕉') // ['苹果', '橙子']\n * ```\n */\nexport function remove<T>(array: T[], item: T): T[] {\n return array.filter(i => i !== item)\n}\n\n/**\n * 数组去重,移除数组中的重复元素\n * @param array 原始数组\n * @returns 去重后的新数组,保持原始顺序\n * @group Array\n * @example\n * ```ts\n * const numbers = [1, 2, 2, 3, 3, 4, 5, 5]\n * const uniqueArray = unique(numbers) // [1, 2, 3, 4, 5]\n *\n * // 对象数组会基于引用去重,内容相同但引用不同的对象会被视为不同元素\n * const objArray = [{id: 1}, {id: 2}, {id: 1}]\n * const uniqueObjArray = unique(objArray) // [{id: 1}, {id: 2}, {id: 1}]\n * ```\n */\nexport function unique<T>(array: T[]): T[] {\n return Array.from(new Set(array))\n}\n\n/**\n * 将数组分成指定大小的块\n * @param array 原始数组\n * @param size 每个块的大小,必须为正整数\n * @returns 二维数组,每个子数组最多包含 size 个元素\n * @group Array\n * @example\n * ```ts\n * const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n * const chunks = chunk(numbers, 3)\n * // 结果: [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]\n *\n * // 如果 size 小于等于 0,则返回包含原始数组的数组\n * chunk(numbers, 0) // [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]]\n * ```\n */\nexport function chunk<T>(array: T[], size: number): T[][] {\n if (size <= 0)\n return [array]\n\n const result: T[][] = []\n for (let i = 0; i < array.length; i += size) {\n result.push(array.slice(i, i + size))\n }\n\n return result\n}\n\n/**\n * 获取数组中的最后一个元素\n * @param array 数组\n * @returns 最后一个元素,如果数组为空则返回 undefined\n * @group Array\n * @example\n * ```ts\n * const numbers = [1, 2, 3, 4, 5]\n * const lastNumber = last(numbers) // 5\n *\n * const empty = []\n * const lastEmpty = last(empty) // undefined\n * ```\n */\nexport function last<T>(array: T[]): T | undefined {\n return array.length > 0 ? array[array.length - 1] : undefined\n}\n\n/**\n * 获取数组中的第一个元素\n * @param array 数组\n * @returns 第一个元素,如果数组为空则返回 undefined\n * @group Array\n * @example\n * ```ts\n * const numbers = [1, 2, 3, 4, 5]\n * const firstNumber = first(numbers) // 1\n *\n * const empty = []\n * const firstEmpty = first(empty) // undefined\n * ```\n */\nexport function first<T>(array: T[]): T | undefined {\n return array.length > 0 ? array[0] : undefined\n}\n\n/**\n * 随机打乱数组元素顺序\n * @param array 原始数组\n * @returns 打乱后的新数组,不会修改原始数组\n * @group Array\n * @example\n * ```ts\n * const numbers = [1, 2, 3, 4, 5]\n * const shuffled = shuffle(numbers)\n * // 可能的结果: [3, 1, 5, 2, 4]\n * console.log(numbers) // 原数组不变: [1, 2, 3, 4, 5]\n * ```\n */\nexport function shuffle<T>(array: T[]): T[] {\n const result = [...array]\n\n for (let i = result.length - 1; i > 0; i--) {\n const j = Math.floor(Math.random() * (i + 1));\n [result[i], result[j]] = [result[j] as T, result[i] as T]\n }\n\n return result\n}\n\n/**\n * 从数组中随机选择一个元素\n * @param array 数组\n * @returns 随机选择的元素,如果数组为空则返回 undefined\n * @group Array\n * @example\n * ```ts\n * const fruits = ['苹果', '香蕉', '橙子', '梨', '葡萄']\n * const randomFruit = sample(fruits)\n * // 可能返回: '香蕉'\n *\n * const empty = []\n * const emptyResult = sample(empty) // undefined\n * ```\n */\nexport function sample<T>(array: T[]): T | undefined {\n if (array.length === 0)\n return undefined\n const index = Math.floor(Math.random() * array.length)\n return array[index]\n}\n\n/**\n * 比较两个数组是否相等(元素顺序和值都相同)\n * @param a 第一个数组\n * @param b 第二个数组\n * @returns 如果两个数组长度相同且对应位置的元素全部相等则返回 true,否则返回 false\n * @group Array\n * @example\n * ```ts\n * isEqual([1, 2, 3], [1, 2, 3]) // true\n * isEqual([1, 2, 3], [1, 3, 2]) // false,顺序不同\n * isEqual([1, 2, 3], [1, 2]) // false,长度不同\n *\n * // 对象比较是基于引用的\n * const obj = { id: 1 }\n * isEqual([obj], [obj]) // true,同一个对象引用\n * isEqual([{ id: 1 }], [{ id: 1 }]) // false,不同对象引用\n * ```\n */\nexport function isEqual<T>(a: T[], b: T[]): boolean {\n if (a.length !== b.length)\n return false\n return a.every((item, index) => item === b[index])\n}\n\n/**\n * 根据条件对数组中的元素进行分组\n * @param array 原始数组\n * @param keyFn 用于生成分组键的函数,接收数组元素并返回用作分组键的值\n * @returns 分组后的对象,键为分组键,值为对应的元素数组\n * @group Array\n * @example\n * ```ts\n * const people = [\n * { name: '张三', age: 25 },\n * { name: '李四', age: 30 },\n * { name: '王五', age: 25 },\n * { name: '赵六', age: 30 }\n * ]\n *\n * // 按年龄分组\n * const groupedByAge = groupBy(people, person => person.age)\n * // 结果:\n * // {\n * // 25: [{ name: '张三', age: 25 }, { name: '王五', age: 25 }],\n * // 30: [{ name: '李四', age: 30 }, { name: '赵六', age: 30 }]\n * // }\n *\n * // 使用字符串键\n * const groupedByAgeRange = groupBy(people, person =>\n * person.age < 30 ? '青年' : '成年')\n * // 结果:\n * // {\n * // '青年': [{ name: '张三', age: 25 }, { name: '王五', age: 25 }],\n * // '成年': [{ name: '李四', age: 30 }, { name: '赵六', age: 30 }]\n * // }\n * ```\n */\nexport function groupBy<T, K extends string | number | symbol>(array: T[], keyFn: (item: T) => K): Record<K, T[]> {\n return array.reduce((result, item) => {\n const key = keyFn(item);\n (result[key] = result[key] || []).push(item)\n return result\n }, {} as Record<K, T[]>)\n}\n\n/**\n * 在选项数组前添加一个\"全部\"选项\n *\n * @param options - 原始选项数组\n * @param config - 配置选项\n * @param config.name - 选项标签的字段名 (默认为 'label')\n * @param config.value - \"全部\"选项的值 (默认为 '')\n * @param config.valueKey - 选项值的字段名 (默认为 'value')\n * @returns 添加了\"全部\"选项的新数组\n *\n * @group Array\n * @example\n * ```ts\n * // 基本用法\n * const options = [\n * { label: '选项1', value: 1 },\n * { label: '选项2', value: 2 }\n * ]\n * const result = appendUniversalOption(options)\n * // 结果: [\n * // { label: '全部', value: '' },\n * // { label: '选项1', value: 1 },\n * // { label: '选项2', value: 2 }\n * // ]\n *\n * // 自定义字段名和值\n * const customOptions = [\n * { text: '选项1', id: 1 },\n * { text: '选项2', id: 2 }\n * ]\n * const customResult = appendUniversalOption(customOptions, {\n * name: 'text',\n * valueKey: 'id',\n * value: 0\n * })\n * // 结果: [\n * // { text: '全部', id: 0 },\n * // { text: '选项1', id: 1 },\n * // { text: '选项2', id: 2 }\n * // ]\n * ```\n */\nexport function appendUniversalOption<T extends Record<string, any>, V = any>(\n options: T[],\n {\n name = 'label',\n value = '' as V,\n valueKey = 'value',\n }: {\n name?: string\n value?: V\n valueKey?: string\n } = {},\n): T[] {\n return [\n {\n [name]: '全部',\n [valueKey]: value,\n } as unknown as T,\n ...options,\n ]\n}\n\n/**\n * 递归重命名树形结构节点的属性。\n *\n * @param tree - 需要处理的树形数据(根节点数组)\n * @param renameMap - 属性重命名映射对象,格式为 `{ oldKey: newKey }`\n * @param childKey - 子节点的键名(默认为 `'children'`)\n * @param deleteOldKeys - 是否删除旧属性(默认 `true`)\n * @returns 处理后的树形结构数组\n *\n * @group Array\n * @example\n * const tree = [\n * { id: 1, name: 'Node 1', children: [...] }\n * ];\n * const renamedTree = renameTreeNodes(tree, { name: 'label' });\n * // 输出:节点中的 `name` 被替换为 `label`,且旧属性被删除\n */\nexport function renameTreeNodes(\n tree: any[],\n renameMap: Record<string, string>,\n childKey: string = 'children',\n deleteOldKeys: boolean = true,\n): any[] {\n return tree.map((node) => {\n const newNode = { ...node }\n\n // 重命名属性\n Object.entries(renameMap).forEach(([oldKey, newKey]) => {\n if (hasOwnProp(newNode, oldKey)) {\n newNode[newKey] = newNode[oldKey]\n if (deleteOldKeys) {\n delete newNode[oldKey]\n }\n }\n })\n\n // 递归处理子节点\n if (Array.isArray(newNode[childKey])) {\n newNode[childKey] = renameTreeNodes(\n newNode[childKey],\n renameMap,\n childKey,\n deleteOldKeys,\n )\n }\n\n return newNode\n })\n}\n\n/**\n * 递归转换树形结构的节点,支持重命名、新增、过滤属性。\n *\n * @param tree - 需要处理的树形数据(根节点数组)\n * @param transformer - 转换函数,接收当前节点和子节点,返回处理后的节点\n * @param childKey - 子节点的键名(默认为 `'children'`)\n * @returns 转换后的树形结构数组\n *\n * @group Array\n * @example\n * // 重命名 `name` 为 `label`,并添加 `isLeaf` 属性\n * const transformedTree = transformTree(tree, (node, children) => ({\n * id: node.id,\n * label: node.name,\n * isLeaf: children.length === 0,\n * children,\n * }));\n */\nexport function transformTree(\n tree: any[],\n transformer: (node: any, children: any[]) => any,\n childKey: string = 'children',\n): any[] {\n return tree.map((node) => {\n const children = node[childKey] ? transformTree(node[childKey], transformer, childKey) : []\n return transformer(node, children)\n })\n}\n\ntype KeysMatching<T, V> = {\n [K in keyof T]-?: T[K] extends V ? K : never\n}[keyof T]\n/**\n * 数组转为对象\n * @param arr - 原始数组\n * @param key - 数组对象键\n * @returns 对应键的对象\n * @group Array\n * @example\n * ```ts\n * const arr = [{ key: 'tom', name: '汤姆' }, { key: 'jack', name: '杰克' }]\n * arrayToObject(arr) // { tom: { key: 'tom', name: '汤姆' }, jack: { key: 'jack', name: '杰克' } }\n *\n * // key 值为空\n * const arr = [{ key: 'tom', name: '汤姆' }, { key: '', name: '杰克' }]\n * arrayToObject(arr) // { tom: { key: 'tom', name: '汤姆' } }\n * ```\n */\nexport function arrayToObject<T>(\n arr: T[],\n key: KeysMatching<T, string | number>,\n): Record<string, T> {\n const result: Record<string, T> = {}\n for (const item of arr) {\n const K = item[key] // K 在这里被 TS 推断为 string | number\n if (!K)\n continue\n result[K as string] = item\n }\n return result\n}\n\n/**\n * 替换数组数据中指定字段的 `&nbsp;` 为不换行空格\n *\n * @param {Array<Record<string, any>>} arr - 数组\n * @param {string} key - 需要处理的字段名\n * @returns {Array<Record<string, any>>} 处理后的数据数组\n *\n * @group String\n * @example\n * ```ts\n * // 基本用法\n * const data = [\n * { name: 'John&nbsp;Doe', age: 30 },\n * { name: 'Jane&nbsp;&nbsp;Smith', age: 25 }\n * ]\n * const result = arrayReplaceNBSP(data, 'name')\n * // 结果: [\n * // { name: 'John Doe', age: 30 },\n * // { name: 'Jane Smith', age: 25 }\n * // ]\n *\n * // 空数组情况\n * const emptyData = []\n * const result = arrayReplaceNBSP(emptyData, 'name')\n * // 结果: []\n * ```\n */\nexport function arrayReplaceNBSP<T extends Record<string, string | number | boolean | object>>(\n arr: T[],\n key: string,\n): T[] {\n if (arr.length) {\n return arr.map((item) => {\n if (typeof item[key] === 'string') {\n // 创建一个新对象,不修改原对象\n return {\n ...item,\n [key]: replaceNBSP(item[key] as string),\n }\n }\n return item\n })\n }\n\n return []\n}\n","import type { Dayjs, ManipulateType, OpUnitType, QUnitType } from 'dayjs'\n/**\n * @module 日期时间\n * @description 提供各种日期时间处理函数,包括日期格式化、日期计算、比较等实用功能。基于 dayjs 库实现。\n */\nimport dayjs from 'dayjs'\nimport isBetween from 'dayjs/plugin/isBetween'\nimport isSameOrAfter from 'dayjs/plugin/isSameOrAfter'\nimport isSameOrBefore from 'dayjs/plugin/isSameOrBefore'\nimport relativeTime from 'dayjs/plugin/relativeTime'\nimport { isNaN, isNumber } from '../is'\n\n// 导入本地化语言\nimport 'dayjs/locale/zh-cn'\n\n// 设置全局语言为中文\ndayjs.locale('zh-cn')\n\n/**\n * 表示日期的各种类型,可以是日期对象、日期字符串或时间戳\n */\nexport type DateLike = Date | string | number\n\n// 注册插件\ndayjs.extend(relativeTime)\ndayjs.extend(isSameOrBefore)\ndayjs.extend(isSameOrAfter)\ndayjs.extend(isBetween)\n\n// 可以按需导入更多插件\n// import weekOfYear from 'dayjs/plugin/weekOfYear'\n// import isLeapYear from 'dayjs/plugin/isLeapYear'\n// import customParseFormat from 'dayjs/plugin/customParseFormat'\n// dayjs.extend(weekOfYear)\n// dayjs.extend(isLeapYear)\n// dayjs.extend(customParseFormat)\n\n/**\n * 创建 dayjs 对象\n * @param date 日期参数,可以是日期对象、时间戳或日期字符串\n * @returns dayjs 对象\n * @group Date\n * @example\n * ```ts\n * createDate() // 当前日期时间\n * createDate('2023-05-15') // 指定日期\n * createDate(1684123456000) // 时间戳\n * ```\n */\nexport function createDate(date?: DateLike | Dayjs): Dayjs {\n return dayjs(date)\n}\n\n/**\n * 判断时间戳是否为毫秒级时间戳\n * @param value 要检查的值\n * @returns 如果是毫秒级时间戳则返回 true,否则返回 false\n * @group Date\n * @example\n * ```ts\n * isMillisecondTimestamp(1673740800000) // true,13位数字\n * isMillisecondTimestamp(1673740800) // false,10位数字,秒级时间戳\n * isMillisecondTimestamp('1673740800000') // false, 字符串不是时间戳\n * isMillisecondTimestamp(new Date()) // false,日期对象不是时间戳\n * ```\n */\nexport function isMillisecondTimestamp(value: unknown): boolean {\n if (!isNumber(value) || value.toString().length !== 13)\n return false\n\n const date = new Date(value)\n return !isNaN(date.getTime())\n}\n\n/**\n * 转换为 dayjs 可接收的参数格式\n * @param value 日期参数,可以是日期对象、时间戳(秒或毫秒)或日期字符串\n * @returns 转换后的参数,如果是秒级时间戳则转为毫秒级,其他类型保持不变\n * @group Date\n * @example\n * ```ts\n * convertToDayjsParam(1673740800) // 1673740800000,秒转为毫秒\n * convertToDayjsParam(1673740800000) // 1673740800000,毫秒保持不变\n * convertToDayjsParam(new Date()) // Date对象,保持不变\n * convertToDayjsParam('2023-01-15') // '2023-01-15',字符串保持不变\n * ```\n */\nexport function convertToDayjsParam(value: DateLike) {\n // 如果是数字,且是10位数字,则可能是秒级时间戳,需要转为毫秒\n if (isNumber(value) && String(value).length === 10) {\n return value * 1000\n }\n return value\n}\n\n/**\n * 格式化日期为指定格式的字符串\n * @param date 日期对象、时间戳或日期字符串\n * @param format 格式字符串,支持的占位符请参考 [dayjs 文档](https://day.js.org/docs/zh-CN/durations/format#%E6%94%AF%E6%8C%81%E7%9A%84%E6%A0%BC%E5%BC%8F%E5%8C%96%E5%8D%A0%E4%BD%8D%E7%AC%A6%E5%88%97%E8%A1%A8)\n * @returns 格式化后的日期字符串\n * @group Date\n * @example\n * ```ts\n * formatDate(new Date(), 'YYYY-MM-DD HH:mm:ss') // \"2023-05-16 14:30:45\"\n * formatDate('2023-05-15', 'YYYY年MM月DD日') // \"2023年05月15日\"\n * formatDate(1684123456000, 'MM/DD/YYYY') // \"05/15/2023\"\n * ```\n */\nexport function formatDate(date: DateLike, format = 'YYYY-MM-DD'): string {\n return dayjs(convertToDayjsParam(date)).format(format)\n}\n\n/**\n * 将日期格式化为完整的时间字符串(YYYY-MM-DD HH:mm:ss)\n * @param date 日期对象、时间戳或日期字符串\n * @returns 格式为 YYYY-MM-DD HH:mm:ss 的日期时间字符串\n * @group Date\n * @example\n * ```ts\n * formatFullTime(new Date()) // \"2023-05-16 14:30:45\"\n * formatFullTime('2023-05-15') // \"2023-05-15 00:00:00\"\n * formatFullTime(1684123456) // \"2023-05-15 10:30:56\"(秒级时间戳会被自动转换)\n * ```\n */\nexport function formatFullTime(date: DateLike) {\n return formatDate(date, 'YYYY-MM-DD HH:mm:ss')\n}\n\n/**\n * 获取当前日期时间的时间戳\n * @returns 当前时间戳(毫秒)\n * @group Date\n * @example\n * ```ts\n * now() // 例如: 1684123456789\n * ```\n */\nexport function now(): number {\n return Date.now()\n}\n\n/**\n * 解析日期字符串为日期对象\n * @param dateStr 日期字符串\n * @returns 日期对象\n * @throws 如果日期格式无效,抛出 TypeError\n * @group Date\n * @example\n * ```ts\n * parseDate('2023-05-15') // Date 对象: Mon May 15 2023 00:00:00\n * parseDate('2023/05/15 14:30:45') // Date 对象: Mon May 15 2023 14:30:45\n * parseDate('invalid date') // 抛出 TypeError: 无效的日期格式\n * ```\n */\nexport function parseDate(dateStr: string): Date {\n const d = dayjs(dateStr)\n if (!d.isValid())\n throw new TypeError('无效的日期格式')\n return d.toDate()\n}\n\n/**\n * 计算两个日期之间的差异\n * @param date1 第一个日期\n * @param date2 第二个日期\n * @param unit 计量单位,默认为 'day',可以是 'year', 'month', 'week', 'day', 'hour', 'minute', 'second', 'millisecond'\n * @returns 两个日期之间的差值,正数表示 date1 晚于 date2,负数表示 date1 早于 date2\n * @group Date\n * @example\n * ```ts\n * diff('2023-05-15', '2023-05-10') // 5(相差5天)\n * diff('2023-05-15', '2023-06-15', 'month') // -1(相差1个月,且第一个日期早于第二个)\n * diff('2023-05-15 08:00', '2023-05-15 06:00', 'hour') // 2(相差2小时)\n * ```\n */\nexport function diff(date1: DateLike, date2: DateLike, unit: QUnitType | OpUnitType = 'day'): number {\n return dayjs(convertToDayjsParam(date1)).diff(dayjs(convertToDayjsParam(date2)), unit)\n}\n\n/**\n * 向日期添加指定时间\n * @param date 原始日期\n * @param amount 要添加的数量,可以为负数\n * @param unit 时间单位,默认为 'day',可以是 'year', 'month', 'week', 'day', 'hour', 'minute', 'second', 'millisecond'\n * @returns 添加后的新日期对象\n * @group Date\n * @example\n * ```ts\n * add(new Date('2023-05-15'), 2, 'day') // Date 对象: Wed May 17 2023\n * add('2023-05-15', -1, 'month') // Date 对象: Sat Apr 15 2023\n * add('2023-05-15 12:00', 30, 'minute') // Date 对象: Mon May 15 2023 12:30:00\n * ```\n */\nexport function add(date: DateLike, amount: number, unit: ManipulateType = 'day'): Date {\n return dayjs(convertToDayjsParam(date)).add(amount, unit).toDate()\n}\n\n/**\n * 向日期添加指定天数\n * @param date 原始日期\n * @param days 要添加的天数(可以为负数)\n * @returns 添加天数后的新日期对象\n * @group Date\n * @example\n * ```ts\n * addDays(new Date('2023-05-15'), 5) // Date 对象: Sat May 20 2023\n * addDays('2023-05-15', -3) // Date 对象: Fri May 12 2023\n * ```\n */\nexport function addDays(date: DateLike, days: number): Date {\n return add(convertToDayjsParam(date), days, 'day')\n}\n\n/**\n * 向日期添加指定月数\n * @param date 原始日期\n * @param months 要添加的月数(可以为负数)\n * @returns 添加月数后的新日期对象\n * @group Date\n * @example\n * ```ts\n * addMonths(new Date('2023-05-15'), 2) // Date 对象: Sat Jul 15 2023\n * addMonths('2023-05-31', 1) // Date 对象: Fri Jun 30 2023(注意月份天数自动调整)\n * addMonths('2023-01-15', -3) // Date 对象: Wed Oct 15 2022\n * ```\n */\nexport function addMonths(date: DateLike, months: number): Date {\n return add(convertToDayjsParam(date), months, 'month')\n}\n\n/**\n * 向日期添加指定年数\n * @param date 原始日期\n * @param years 要添加的年数(可以为负数)\n * @returns 添加年数后的新日期对象\n * @group Date\n * @example\n * ```ts\n * addYears(new Date('2023-05-15'), 1) // Date 对象: Wed May 15 2024\n * addYears('2023-05-15', -3) // Date 对象: Fri May 15 2020\n * addYears('2024-02-29', 1) // Date 对象: Fri Feb 28 2025(注意闰年自动调整)\n * ```\n */\nexport function addYears(date: DateLike, years: number): Date {\n return add(convertToDayjsParam(date), years, 'year')\n}\n\n/**\n * 获取指定日期是一周中的第几天\n * @param date 日期\n * @param startOnMonday 是否从周一开始计算(默认为 false,即从周日开始)\n * @returns 一周中的第几天(0-6),周日为 0,周六为 6;如果 startOnMonday 为 true,则周一为 0,周日为 6\n * @group Date\n * @example\n * ```ts\n * getDayOfWeek(new Date('2023-05-15')) // 1(周一,从周日开始算是第1天)\n * getDayOfWeek('2023-05-15', true) // 0(周一,从周一开始算是第0天)\n * getDayOfWeek('2023-05-14') // 0(周日,从周日开始算是第0天)\n * getDayOfWeek('2023-05-14', true) // 6(周日,从周一开始算是第6天)\n * ```\n */\nexport function getDayOfWeek(date: DateLike, startOnMonday = false): number {\n const d = dayjs(convertToDayjsParam(date))\n const day = d.day()\n if (startOnMonday) {\n return day === 0 ? 6 : day - 1\n }\n return day\n}\n\n/**\n * 检查日期是否在指定范围内\n * @param date 要检查的日期\n * @param startDate 范围起始日期\n * @param endDate 范围结束日期\n * @returns 如果日期在指定范围内(不包括边界)则返回 true,否则返回 false\n * @group Date\n * @example\n * ```ts\n * isDateInRange('2023-05-15', '2023-05-10', '2023-05-20') // true\n * isDateInRange('2023-05-15', '2023-05-15', '2023-05-20') // false(不包括开始日期)\n * isDateInRange('2023-05-15', '2023-05-10', '2023-05-15') // false(不包括结束日期)\n * ```\n */\nexport function isDateInRange(date: DateLike, startDate: DateLike, endDate: DateLike): boolean {\n const d = dayjs(convertToDayjsParam(date))\n return d.isAfter(dayjs(convertToDayjsParam(startDate))) && d.isBefore(dayjs(convertToDayjsParam(endDate)))\n}\n\n/**\n * 获取指定月份的天数\n * @param year 年份\n * @param month 月份(0-11),0 表示一月,11 表示十二月\n * @returns 该月的天数\n * @group Date\n * @example\n * ```ts\n * getDaysInMonth(2023, 1) // 28(2023年2月有28天)\n * getDaysInMonth(2024, 1) // 29(2024年2月有29天,闰年)\n * getDaysInMonth(2023, 0) // 31(2023年1月有31天)\n * ```\n */\nexport function getDaysInMonth(year: number, month: number): number {\n return dayjs(new Date(year, month, 1)).daysInMonth()\n}\n\n/**\n * 获取相对时间描述\n * @param date 日期\n * @param baseDate 基准日期,默认为当前时间\n * @returns 相对时间描述,如\"几分钟前\"、\"几天后\"等\n * @group Date\n * @example\n * ```ts\n * fromNow(new Date(Date.now() - 5 * 60 * 1000)) // \"5分钟前\"\n * fromNow(new Date(Date.now() + 24 * 60 * 60 * 1000)) // \"1天内\"\n * fromNow('2023-01-01', '2023-01-05') // \"4天前\"\n * ```\n */\nexport function fromNow(date: DateLike, baseDate?: DateLike): string {\n date = convertToDayjsParam(date)\n baseDate = baseDate && convertToDayjsParam(baseDate)\n if (baseDate)\n return dayjs(date).from(dayjs(baseDate))\n return dayjs(date).fromNow()\n}\n\n/**\n * 获取日期的开始时间\n * @param date 日期\n * @param unit 单位,可以是 'year', 'month', 'week', 'day', 'hour', 'minute', 'second'\n * @returns 单位开始时间的日期对象\n * @group Date\n * @example\n * ```ts\n * startOf(new Date('2023-05-15 15:30:45'), 'day') // Date 对象: Mon May 15 2023 00:00:00\n * startOf('2023-05-15 15:30:45', 'month') // Date 对象: Mon May 01 2023 00:00:00\n * startOf('2023-05-15 15:30:45', 'hour') // Date 对象: Mon May 15 2023 15:00:00\n * ```\n */\nexport function startOf(date: DateLike, unit: OpUnitType): Date {\n return dayjs(convertToDayjsParam(date)).startOf(unit).toDate()\n}\n\n/**\n * 获取日期的结束时间\n * @param date 日期\n * @param unit 单位,可以是 'year', 'month', 'week', 'day', 'hour', 'minute', 'second'\n * @returns 单位结束时间的日期对象\n * @group Date\n * @example\n * ```ts\n * endOf(new Date('2023-05-15 15:30:45'), 'day') // Date 对象: Mon May 15 2023 23:59:59.999\n * endOf('2023-05-15 15:30:45', 'month') // Date 对象: Wed May 31 2023 23:59:59.999\n * endOf('2023-05-15 15:30:45', 'hour') // Date 对象: Mon May 15 2023 15:59:59.999\n * ```\n */\nexport function endOf(date: DateLike, unit: OpUnitType): Date {\n return dayjs(convertToDayjsParam(date)).endOf(unit).toDate()\n}\n\n/**\n * 格式化日期为人类友好的格式\n * @param date 日期\n * @returns 人类友好的日期描述,如\"今天 HH:mm\"、\"昨天 HH:mm\"、\"明天 HH:mm\"或\"YYYY-MM-DD HH:mm\"\n * @group Date\n * @example\n * ```ts\n * formatHumanReadable(new Date()) // \"今天 15:30\"\n * formatHumanReadable(new Date(Date.now() - 24 * 60 * 60 * 1000)) // \"昨天 15:30\"\n * formatHumanReadable(new Date(Date.now() + 24 * 60 * 60 * 1000)) // \"明天 15:30\"\n * formatHumanReadable('2023-01-01') // \"2023-01-01 00:00\"\n * ```\n */\nexport function formatHumanReadable(date: DateLike): string {\n const d = dayjs(convertToDayjsParam(date))\n const now = dayjs()\n\n if (d.isSame(now, 'day'))\n return `今天 ${d.format('HH:mm')}`\n if (d.isSame(now.subtract(1, 'day'), 'day'))\n return `昨天 ${d.format('HH:mm')}`\n if (d.isSame(now.add(1, 'day'), 'day'))\n return `明天 ${d.format('HH:mm')}`\n if (d.isSame(now, 'year'))\n return d.format('M月D日 HH:mm')\n return d.format('YYYY年M月D日 HH:mm')\n}\n","/**\n * @module 数字处理\n * @description 提供各种数字处理函数,包括数字格式化、计算、范围控制等实用功能\n */\n\n/**\n * 将数字四舍五入到指定小数位\n * @param num 要处理的数字\n * @param precision 小数位数,默认为0(整数)\n * @returns 四舍五入后的数字\n * @group Number\n * @example\n * ```ts\n * round(3.1415) // 3\n * round(3.1415, 2) // 3.14\n * round(3.1415, 3) // 3.142\n * round(3.9999) // 4\n * ```\n */\nexport function round(num: number, precision = 0): number {\n const factor = 10 ** precision\n return Math.round(num * factor) / factor\n}\n\n/**\n * 将数字格式化为带千位分隔符的字符串\n * @param num 要格式化的数字\n * @param locale 区域设置,默认为浏览器默认区域\n * @returns 格式化后的字符串\n * @group Number\n * @example\n * ```ts\n * formatThousands(1234567) // '1,234,567'(根据浏览器默认区域可能有所不同)\n * formatThousands(1234567.89, 'en-US') // '1,234,567.89'\n * formatThousands(1234567.89, 'de-DE') // '1.234.567,89'\n * ```\n */\nexport function formatThousands(num: number, locale?: string): string {\n return num.toLocaleString(locale)\n}\n\n/**\n * 将数字格式化为货币字符串\n * @param value 要格式化的数字\n * @param options 格式化选项\n * @param options.currency 货币代码(如 'CNY', 'USD'),默认为 'CNY'\n * @param options.locale 地区设置(如 'zh-CN', 'en-US'),默认为 'zh-CN'\n * @param options.minimumFractionDigits 最小小数位数,默认为 2\n * @param options.maximumFractionDigits 最大小数位数,默认为 2\n * @returns 格式化后的货币字符串\n * @group Number\n * @example\n * ```ts\n * formatCurrency(1234.56) // '¥1,234.56'\n * formatCurrency(1234.56, { currency: 'USD', locale: 'en-US' }) // '$1,234.56'\n * formatCurrency(1234.56789, { maximumFractionDigits: 4 }) // '¥1,234.5679'\n * formatCurrency(1234, { minimumFractionDigits: 0 }) // '¥1,234'\n * ```\n */\nexport function formatCurrency(\n value: number,\n options: {\n currency?: string\n locale?: string\n minimumFractionDigits?: number\n maximumFractionDigits?: number\n } = {},\n): string {\n const {\n currency = 'CNY',\n locale = 'zh-CN',\n minimumFractionDigits = 2,\n maximumFractionDigits = 2,\n } = options\n\n return new Intl.NumberFormat(locale, {\n style: 'currency',\n currency,\n minimumFractionDigits,\n maximumFractionDigits,\n }).format(value)\n}\n\n/**\n * 确保数字在指定范围内\n * @param num 要限制范围的数字\n * @param min 最小值\n * @param max 最大值\n * @returns 在指定范围内的数字:如果小于最小值返回最小值,如果大于最大值返回最大值\n * @group Number\n * @example\n * ```ts\n * clamp(5, 0, 10) // 5 - 在范围内,保持不变\n * clamp(-5, 0, 10) // 0 - 小于最小值,返回最小值\n * clamp(15, 0, 10) // 10 - 大于最大值,返回最大值\n * ```\n */\nexport function clamp(num: number, min: number, max: number): number {\n return Math.min(Math.max(num, min), max)\n}\n\n/**\n * 生成指定范围内的随机整数(包含边界值)\n * @param min 最小值(包含)\n * @param max 最大值(包含)\n * @returns 指定范围内的随机整数\n * @group Number\n * @example\n * ```ts\n * randomInt(1, 10) // 返回 1 到 10 之间的随机整数,包括 1 和 10\n * randomInt(0, 1) // 返回 0 或 1\n * randomInt(5, 5) // 总是返回 5\n * ```\n */\nexport function randomInt(min: number, max: number): number {\n min = Math.ceil(min)\n max = Math.floor(max)\n return Math.floor(Math.random() * (max - min + 1)) + min\n}\n\n/**\n * 检查一个数字是否为偶数\n * @param num 要检查的数字\n * @returns 如果是偶数则返回 true,否则返回 false\n * @group Number\n * @example\n * ```ts\n * isEven(2) // true\n * isEven(3) // false\n * isEven(0) // true\n * isEven(-4) // true\n * ```\n */\nexport function isEven(num: number): boolean {\n return num % 2 === 0\n}\n\n/**\n * 检查一个数字是否为奇数\n * @param num 要检查的数字\n * @returns 如果是奇数则返回 true,否则返回 false\n * @group Number\n * @example\n * ```ts\n * isOdd(3) // true\n * isOdd(2) // false\n * isOdd(0) // false\n * isOdd(-3) // true\n * ```\n */\nexport function isOdd(num: number): boolean {\n return !isEven(num)\n}\n\n/**\n * 计算百分比值\n * @param value 当前值\n * @param total 总值\n * @param precision 结果保留的小数位数,默认为2\n * @returns 百分比值,如果总值为零则返回 0\n * @group Number\n * @example\n * ```ts\n * percentage(25, 100) // 25\n * percentage(1, 3) // 33.33\n * percentage(1, 3, 0) // 33\n * percentage(5, 0) // 0,避免除以零错误\n * ```\n */\nexport function percentage(value: number, total: number, precision = 2): number {\n if (total === 0)\n return 0\n return round((value / total) * 100, precision)\n}\n\n/**\n * 将数值转换为带\"万\"单位的字符串\n * @param num 要转换的数值\n * @param fractionDigits 小数位数,默认为2\n * @returns 转换后的字符串,如果值大于等于10000则转为\"万\"单位\n * @group Number\n * @example\n * ```ts\n * formatNumberWithTenThousand(1234) // '1234'\n * formatNumberWithTenThousand(12345) // '1.23万'\n * formatNumberWithTenThousand(12345, 1) // '1.2万'\n * formatNumberWithTenThousand(0) // '0'\n * ```\n */\nexport function formatNumberWithTenThousand(num: number, fractionDigits = 2): string {\n if (!num) {\n return '0'\n }\n if (num >= 10000) {\n // 保留两位小数\n return `${(num / 10000).toFixed(fractionDigits)}万`\n }\n else {\n return num.toString()\n }\n}\n","/**\n * 延迟指定的毫秒数\n *\n * @param {number} ms - 需要延迟的毫秒数\n * @returns {Promise<void>} 返回一个在指定时间后resolve的Promise\n * @group Promise\n * @example\n * ```ts\n * // 延迟2秒\n * await delay(2000)\n * console.log('2秒后执行')\n *\n * // 在异步函数中使用\n * async function fetchWithDelay() {\n * await delay(1000)\n * return fetch('/api/data')\n * }\n * ```\n */\nexport function delay(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms))\n}\n","import { objectToQueryString } from '../object'\n\n/**\n * 将对象转换为URL查询字符串\n *\n * @deprecated 请使用 objectToQueryString 函数代替,它在 object 模块中。该函数将在下一个主要版本中移除。\n * @param {Record<string, any>} params - 需要转换的对象\n * @returns {string} 转换后的查询字符串,如果有参数则以?开头\n * @group Url\n * @example\n * ```ts\n * // 基本用法\n * getQueryStringify({ name: 'John', age: 30 })\n * // 返回: ?name=John&age=30\n *\n * // 包含对象的情况\n * getQueryStringify({ user: { name: 'John', age: 30 }, active: true })\n * // 返回: ?user={\"name\":\"John\",\"age\":30}&active=true\n *\n * // 空对象\n * getQueryStringify({})\n * // 返回: ''\n *\n * // null 或 undefined\n * getQueryStringify(null)\n * // 返回: ''\n * ```\n */\nexport function getQueryStringify(params: Record<string, any> | null | undefined): string {\n if (!params)\n return ''\n\n const queryString = objectToQueryString(params)\n\n if (queryString)\n return `?${queryString}`\n\n return ''\n}\n"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pmun/utils",
3
3
  "type": "module",
4
- "version": "0.2.4",
4
+ "version": "0.3.1",
5
5
  "description": "Sunpm 的主观个人工具函数库",
6
6
  "author": "sunpm",
7
7
  "license": "MIT",