qsu 1.17.0 → 1.19.0

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.
Files changed (57) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +166 -12
  3. package/dist/_types/global.d.ts +21 -4
  4. package/dist/array/_naturalCompare.d.ts +11 -0
  5. package/dist/array/_naturalCompare.js +1 -0
  6. package/dist/array/arrCount.d.ts +1 -1
  7. package/dist/array/arrMove.d.ts +1 -1
  8. package/dist/array/arrRepeat.d.ts +1 -1
  9. package/dist/array/sortByObjectKey.js +1 -1
  10. package/dist/array/sortNumeric.js +1 -1
  11. package/dist/format/duration.d.ts +1 -1
  12. package/dist/format/duration.js +1 -1
  13. package/dist/format/durationParts.d.ts +10 -0
  14. package/dist/format/durationParts.js +1 -0
  15. package/dist/format/fileSizeFormat.d.ts +2 -2
  16. package/dist/format/fileSizeFormat.js +1 -1
  17. package/dist/format/fileSizeParts.d.ts +11 -0
  18. package/dist/format/fileSizeParts.js +1 -0
  19. package/dist/format/index.d.ts +2 -0
  20. package/dist/format/index.js +1 -1
  21. package/dist/format/numberFormat.js +1 -1
  22. package/dist/format/safeJSONParse.d.ts +1 -1
  23. package/dist/misc/debounce.d.ts +1 -1
  24. package/dist/misc/funcTimes.d.ts +1 -1
  25. package/dist/misc/retry.d.ts +1 -1
  26. package/dist/misc/sleep.d.ts +1 -1
  27. package/dist/misc/throttle.d.ts +1 -1
  28. package/dist/node/file/getFileInfo.d.ts +1 -1
  29. package/dist/node/net/fetchData.d.ts +1 -1
  30. package/dist/node/os/getUptime.d.ts +1 -1
  31. package/dist/object/objDeleteKeyByValue.d.ts +1 -1
  32. package/dist/object/objFindItemRecursiveByKey.d.ts +1 -1
  33. package/dist/object/objGet.d.ts +1 -1
  34. package/dist/object/objInvert.d.ts +1 -1
  35. package/dist/object/objMapKeys.d.ts +1 -1
  36. package/dist/object/objMerge.d.ts +1 -1
  37. package/dist/object/objMergeNewKey.d.ts +1 -1
  38. package/dist/object/objPick.d.ts +1 -1
  39. package/dist/object/objPickBy.d.ts +1 -1
  40. package/dist/object/objTo1d.d.ts +1 -1
  41. package/dist/object/objToArray.d.ts +1 -1
  42. package/dist/object/objToPrettyStr.d.ts +1 -1
  43. package/dist/object/objToQueryString.d.ts +1 -1
  44. package/dist/object/objUpdate.d.ts +1 -1
  45. package/dist/string/deburr.js +1 -1
  46. package/dist/string/pad.d.ts +1 -1
  47. package/dist/string/strBlindRandom.d.ts +1 -1
  48. package/dist/string/strRandom.d.ts +1 -1
  49. package/dist/string/truncate.d.ts +1 -1
  50. package/dist/string/truncate.js +1 -1
  51. package/dist/string/truncateExpect.d.ts +2 -2
  52. package/dist/string/truncateExpect.js +1 -1
  53. package/dist/verify/hasBadWords.js +1 -1
  54. package/dist/web/generateLicense.d.ts +1 -1
  55. package/dist/web/getParsedInfoFromAddress.d.ts +1 -1
  56. package/dist/web/getSlug.d.ts +1 -1
  57. package/package.json +105 -22
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2021-2026 CDGet <jooy2.contact@gmail.com> (https://cdget.com).
3
+ Copyright (c) 2021-2026 CDGet (https://cdget.com).
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -2,29 +2,183 @@
2
2
 
3
3
  # qsu - Quick & Simple Utility
4
4
 
5
- [![license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/jooy2/qsu/blob/main/LICENSE) ![Commit Count](https://img.shields.io/github/commit-activity/y/jooy2/qsu) [![Followers](https://img.shields.io/github/followers/jooy2?style=social)](https://github.com/jooy2) ![Stars](https://img.shields.io/github/stars/jooy2/qsu?style=social)
5
+ [![npm latest package](https://img.shields.io/npm/v/qsu/latest.svg)](https://www.npmjs.com/package/qsu) [![npm downloads](https://img.shields.io/npm/dm/qsu.svg)](https://www.npmjs.com/package/qsu) ![minified size](https://img.shields.io/bundlephobia/min/qsu) ![node version](https://img.shields.io/node/v/qsu) [![license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/jooy2/qsu/blob/main/LICENSE) [![test](https://github.com/jooy2/qsu/actions/workflows/run-test-javascript.yml/badge.svg)](https://github.com/jooy2/qsu/actions/workflows/run-test-javascript.yml)
6
6
 
7
- **qsu** is a library that collects frequently used utility functions. Streamline repetitive code with useful functions. Optimized for modern development environments, it supports various programming languages.
7
+ **qsu** is a library that collects frequently used utility functions slugs, text case, date math, number and file size formatting, deep clone and merge, validation, hashing, file and OS helpers. Stop rewriting the same small helpers in every project and stop pulling in a large toolkit for three of them.
8
8
 
9
- The following are the advantages of the qsu:
9
+ ```javascript
10
+ import { getSlug, fileSizeFormat, objMerge } from 'qsu';
10
11
 
11
- - Fast, lightweight bundle size
12
- - Install and use easily.
13
- - It is suitable for use on websites or applications.
14
- - Documents, prepared for secure data types.
15
- - Reduce defects through fast maintenance and various test cases.
16
- - Support for multiple programming languages for the same operation. (JavaScript, Dart)
12
+ getSlug('Hello World!'); // 'hello-world'
13
+ fileSizeFormat(1000000); // '976.56 KB'
14
+ objMerge({ a: { b: 1 } }, { a: { c: 2 } }); // { a: { b: 1, c: 2 } }
15
+ ```
16
+
17
+ ## Why qsu
18
+
19
+ - **No runtime dependencies.** Nothing is installed alongside it.
20
+ - **Tree-shakeable.** The package is marked side-effect free, so your bundler keeps only the functions you actually import.
21
+ - **ESM only.** Written for modern toolchains, from bundlers to serverless runtimes.
22
+ - **Typed.** TypeScript declarations ship with the package, and the shared option types are importable from `qsu/types`.
23
+ - **Browser-safe by default.** Functions that need a Node.js runtime live behind the `qsu/node` subpath, so the main entry point never reaches for `node:fs` or `node:crypto`.
24
+ - **Predictable.** Arguments are validated and edge cases — `null`, empty values, surrogate pairs, nested arrays — return a sensible result instead of throwing.
25
+ - **Tested.** The suite runs on Node.js 22, 24 and 26 across Linux, macOS and Windows in CI.
26
+
27
+ ## Installation
28
+
29
+ **qsu** requires `Node.js 18` or later.
30
+
31
+ ```bash
32
+ npm install qsu
33
+ ```
34
+
35
+ ```bash
36
+ pnpm add qsu
37
+ ```
38
+
39
+ ```bash
40
+ yarn add qsu
41
+ ```
42
+
43
+ ## How to use
44
+
45
+ Import only the functions you need:
46
+
47
+ ```javascript
48
+ import { today, strCount } from 'qsu';
49
+
50
+ console.log(today()); // '20xx-xx-xx'
51
+ console.log(strCount('123412341234', '1')); // 3
52
+ ```
53
+
54
+ You can also import the package under a single name. It makes qsu's functions easy to spot in a file, but it is not the recommended default: a bundler can still drop untouched functions while every access is a plain property (`_.today()`), but as soon as a name is looked up dynamically (`_[name]()`) or `_` is handed to something else, the whole library has to be kept.
55
+
56
+ ```javascript
57
+ import * as _ from 'qsu';
58
+
59
+ console.log(_.today()); // '20xx-xx-xx'
60
+ console.log(_.strCount('123412341234', '1')); // 3
61
+ ```
62
+
63
+ ### Node.js only functions
64
+
65
+ Functions for the filesystem, hashing, networking and the operating system need a Node.js runtime, so they are published under the `qsu/node` subpath and are not part of the browser-safe entry point:
66
+
67
+ ```javascript
68
+ import { createFile, md5Hash } from 'qsu/node';
69
+
70
+ md5Hash('test'); // '098f6bcd4621d373cade4e832627b4f6'
71
+ await createFile('/home/user/Hello.txt');
72
+ ```
73
+
74
+ Every reference page states whether the function has to be imported from `qsu/node`.
75
+
76
+ ### Importing a single category
77
+
78
+ If you are not running a bundler at all — a script, a serverless function, a test — you can import a single category so that only that category's modules are loaded:
79
+
80
+ ```javascript
81
+ import { arrUnique } from 'qsu/array';
82
+ import { getSlug } from 'qsu/web';
83
+ import { md5Hash } from 'qsu/node/crypto';
84
+ ```
85
+
86
+ ### Types
87
+
88
+ Option types are shared and can be imported directly:
89
+
90
+ ```typescript
91
+ import type { SlugOptions, DurationOptions } from 'qsu/types';
92
+
93
+ const options: SlugOptions = { separator: '_', includeNumbers: false };
94
+ ```
95
+
96
+ ## Examples
97
+
98
+ ```javascript
99
+ import {
100
+ arrUnique,
101
+ duration,
102
+ numberFormat,
103
+ objPick,
104
+ pad,
105
+ strToCamelCase,
106
+ truncate,
107
+ isEmail
108
+ } from 'qsu';
109
+
110
+ // Arrays
111
+ arrUnique([1, 1, 2, 3, 3]); // [1, 2, 3]
112
+
113
+ // Formatting
114
+ numberFormat(1234567); // '1,234,567'
115
+ duration(1234567890); // '14 Days 6 Hours 56 Minutes 7 Seconds'
116
+
117
+ // Objects
118
+ objPick({ a: 1, b: 2, c: 3 }, ['a', 'c']); // { a: 1, c: 3 }
119
+
120
+ // Strings
121
+ strToCamelCase('foo bar'); // 'fooBar'
122
+ truncate('Hello world', 5, '...'); // 'Hello...'
123
+ pad('7', 3, { char: '0', position: 'start' }); // '007'
124
+
125
+ // Validation
126
+ isEmail('abc@example.com'); // true
127
+ ```
128
+
129
+ Optional arguments are passed as an options object, and every option has a documented default:
130
+
131
+ ```javascript
132
+ getSlug('Hello World!', { separator: '_' }); // 'hello_world'
133
+ fileSizeFormat(100000000, 3, true); // '96 MB'
134
+ ```
135
+
136
+ ## API overview
137
+
138
+ Functions are grouped into categories, each with an import subpath of its own.
139
+
140
+ | Category | Import path | Examples |
141
+ | --- | --- | --- |
142
+ | `array` | `qsu/array` | `arrUnique`, `arrGroupByMaxCount`, `sortNumeric` |
143
+ | `date` | `qsu/date` | `today`, `dayDiff`, `createDateListFromRange` |
144
+ | `format` | `qsu/format` | `numberFormat`, `fileSizeFormat`, `duration` |
145
+ | `math` | `qsu/math` | `sum`, `clamp`, `round`, `numPick` |
146
+ | `misc` | `qsu/misc` | `debounce`, `throttle`, `retry`, `sleep` |
147
+ | `object` | `qsu/object` | `objClone`, `objMerge`, `objPick`, `objGet` |
148
+ | `string` | `qsu/string` | `trim`, `truncate`, `strToCamelCase`, `pad` |
149
+ | `verify` | `qsu/verify` | `isEmail`, `isUrl`, `isEmpty`, `isEqual` |
150
+ | `web` | `qsu/web` | `getSlug`, `escapeHtml`, `isMobile`, `isBotAgent` |
151
+ | `crypto` | `qsu/node/crypto` | `md5Hash`, `sha256Hash`, `encodeBase64`, `objectId` |
152
+ | `file` | `qsu/node/file` | `getFileSize`, `moveFile`, `joinFilePath` |
153
+ | `misc` | `qsu/node/misc` | `logBox` |
154
+ | `net` | `qsu/node/net` | `fetchData` |
155
+ | `os` | `qsu/node/os` | `getCpu`, `getRamSize`, `runCommand` |
156
+
157
+ The categories in the top half are exported from `qsu` and are safe to bundle for the browser. The `crypto`, `file`, `net` and `os` categories, and `logBox`, need a Node.js runtime and are exported from `qsu/node`.
17
158
 
18
159
  ## Documentation
19
160
 
20
161
  Installing and using the package and defining all the utility methods can be found on the documentation page below.
21
162
 
22
- - [Installation](https://qsu.cdget.com/installation/javascript)
23
- - [Reference](https://qsu.cdget.com/reference)
163
+ - [Installation](https://qsu.cdget.com/installation)
164
+ - [Reference](https://qsu.cdget.com/reference) — every function, with parameters, defaults and examples
165
+ - [Changelog](https://qsu.cdget.com/changelog/)
166
+
167
+ ## Development
168
+
169
+ The package lives in the [qsu monorepo](https://github.com/jooy2/qsu) under `packages/javascript`. Source is TypeScript in `lib/`, built to `dist/`.
170
+
171
+ ```bash
172
+ npm install # install dev dependencies
173
+ npm test # build, then run the test suite
174
+ npm run build # compile with tsc and minify with terser
175
+ npm run lint # ESLint
176
+ npm run format # Prettier
177
+ ```
24
178
 
25
179
  ## Contributing
26
180
 
27
- Anyone can contribute to the project by reporting new issues or submitting a pull request. For more information, please see [CONTRIBUTING.md](CONTRIBUTING.md).
181
+ Anyone can contribute to the project by reporting new issues or submitting a pull request. For more information, please see [CONTRIBUTING.md](https://github.com/jooy2/qsu/blob/main/CONTRIBUTING.md).
28
182
 
29
183
  ## License
30
184
 
@@ -6,15 +6,32 @@ export type AnyValueObject = {
6
6
  [key: string]: any;
7
7
  };
8
8
  export type DurationUnitName = 'Year' | 'Month' | 'Day' | 'Hour' | 'Minute' | 'Second' | 'Millisecond';
9
- export type DurationOptions = {
10
- useShortString?: boolean;
11
- useSpace?: boolean;
9
+ export type DurationPartsOptions = {
12
10
  withZeroValue?: boolean;
13
- separator?: string;
14
11
  withMilliSeconds?: boolean;
15
12
  maxUnitCount?: number;
16
13
  unit?: DurationUnitName;
17
14
  };
15
+ export type DurationOptions = DurationPartsOptions & {
16
+ useShortString?: boolean;
17
+ useSpace?: boolean;
18
+ separator?: string;
19
+ };
20
+ export type DurationPart = {
21
+ value: number;
22
+ unit: DurationUnitName;
23
+ };
24
+ export type FileSizeStandard = 'jedec' | 'iec' | 'si';
25
+ export type FileSizeUnitDisplay = 'short' | 'long';
26
+ export type FileSizeOptions = {
27
+ standard?: FileSizeStandard;
28
+ unitDisplay?: FileSizeUnitDisplay;
29
+ };
30
+ export type FileSizeParts = {
31
+ value: number;
32
+ unit: string;
33
+ exponent: number;
34
+ };
18
35
  export type RetryOptions = {
19
36
  times?: number;
20
37
  delay?: number;
@@ -0,0 +1,11 @@
1
+ type Run = [number, string, boolean];
2
+ export type NaturalKey = {
3
+ runs: Run[];
4
+ accents: string;
5
+ caseBits: string;
6
+ raw: string;
7
+ };
8
+ export declare function naturalKey(value: unknown): NaturalKey;
9
+ export declare function compareNaturalKey(a: NaturalKey, b: NaturalKey): number;
10
+ export declare function compareNatural(a: unknown, b: unknown): number;
11
+ export {};
@@ -0,0 +1 @@
1
+ const t=/([0-9]+)/,n=/^[0-9]+$/,e=/^0+(?=\d)/,r=/[̀-ͯ]/g,o=/[^̀-ͯ]/g,c=/\s/,s=/[\p{L}\p{M}\p{N}]/u;function a(t){return c.test(t)?0:s.test(t)?3:1}export function naturalKey(c){const s="string"==typeof c?c:String(c??""),u=[];let i="",l="";for(const c of s.split(t)){if(""===c)continue;if(n.test(c)){u.push([2,c.replace(e,""),!0]);continue}const t=c.normalize("NFD"),s=t.replace(r,"");i+=t.replace(o,"");for(const t of s){const n=t.toLowerCase(),e=a(t),r=u[u.length-1];l+=t===n?"0":"1",void 0===r||r[0]!==e||r[2]?u.push([e,n,!1]):r[1]+=n}}return{runs:u,accents:i,caseBits:l,raw:s}}function u(t,n){return t.length!==n.length?t.length<n.length?-1:1:t<n?-1:t>n?1:0}function i(t,n){return t<n?-1:t>n?1:0}export function compareNaturalKey(t,n){const e=Math.max(t.runs.length,n.runs.length);for(let r=0;r<e;r+=1){const e=t.runs[r],o=n.runs[r];if(void 0===e||void 0===o)return void 0===e?-1:1;if(e[0]!==o[0])return e[0]<o[0]?-1:1;const c=e[2]?u(e[1],o[1]):i(e[1],o[1]);if(0!==c)return c}return i(t.accents,n.accents)||i(t.caseBits,n.caseBits)||i(t.raw,n.raw)}export function compareNatural(t,n){return compareNaturalKey(naturalKey(t),naturalKey(n))}
@@ -1,2 +1,2 @@
1
- import type { NumberValueObject } from '../_types/global';
1
+ import type { NumberValueObject } from '../_types/global.js';
2
2
  export declare function arrCount(array: string[] | number[]): NumberValueObject;
@@ -1,2 +1,2 @@
1
- import { PositiveNumber } from '../_types/global';
1
+ import type { PositiveNumber } from '../_types/global.js';
2
2
  export declare function arrMove<N extends number>(array: any[], from: PositiveNumber<N>, to: PositiveNumber<N>): any[];
@@ -1,2 +1,2 @@
1
- import { PositiveNumber } from '../_types/global';
1
+ import type { PositiveNumber } from '../_types/global.js';
2
2
  export declare function arrRepeat<N extends number>(array: any, count: PositiveNumber<N>): any[];
@@ -1 +1 @@
1
- const o=new Intl.Collator([],{numeric:!0});export function sortByObjectKey(r,t,e=!1,n=!1){return n?[...r].sort((r,n)=>e?o.compare(n[t],r[t]):o.compare(r[t],n[t])):[...r].sort((o,r)=>e?o[t]>r[t]?-1:o[t]<r[t]?1:0:o[t]<r[t]?-1:o[t]>r[t]?1:0)}
1
+ import{compareNaturalKey as t,naturalKey as r}from"./_naturalCompare.js";export function sortByObjectKey(o,e,s=!1,n=!1){if(n){const n=o.map(t=>({item:t,sortKey:r(t[e])}));return n.sort((r,o)=>{const e=t(r.sortKey,o.sortKey);return s?-e:e}),n.map(t=>t.item)}return[...o].sort((t,r)=>s?t[e]>r[e]?-1:t[e]<r[e]?1:0:t[e]<r[e]?-1:t[e]>r[e]?1:0)}
@@ -1 +1 @@
1
- const r=new Intl.Collator([],{numeric:!0});export function sortNumeric(o,t=!1){return[...o].sort((o,e)=>t?r.compare(e,o):r.compare(o,e))}
1
+ import{compareNaturalKey as r,naturalKey as e}from"./_naturalCompare.js";export function sortNumeric(t,o=!1){const a=t.map(r=>({value:r,key:e(r)}));return a.sort((e,t)=>{const a=r(e.key,t.key);return o?-a:a}),a.map(r=>r.value)}
@@ -1,2 +1,2 @@
1
- import type { DurationOptions } from '../_types/global';
1
+ import type { DurationOptions } from '../_types/global.js';
2
2
  export declare function duration(milliseconds: number, options?: DurationOptions): string;
@@ -1 +1 @@
1
- const e=[{name:"Year",short:"Y",ms:31536e6},{name:"Month",short:"Mo",ms:2592e6},{name:"Day",short:"D",ms:864e5},{name:"Hour",short:"H",ms:36e5},{name:"Minute",short:"M",ms:6e4},{name:"Second",short:"S",ms:1e3},{name:"Millisecond",short:"ms",ms:1}];function t(e,t,n,o){return`${e}${o?" ":""}${n?t.short:`${t.name}${1===e?"":"s"}`}`}export function duration(n,o){const{useShortString:s=!1,useSpace:r=!0,withZeroValue:a=!1,separator:i=" ",withMilliSeconds:m=!1,maxUnitCount:u,unit:l}={...o};if(l){const o=l.toLowerCase().replace(/s$/,""),a=e.find(e=>e.name.toLowerCase()===o);if(a)return t((c=n/a.ms,Number(c.toFixed(6))),a,s,r)}var c;const h=m?e:e.filter(e=>"Millisecond"!==e.name),f=[];let d=n;for(const e of h){const t=Math.floor(d/e.ms);d-=t*e.ms,f.push({value:t,unit:e})}const M=f.findIndex(e=>0!==e.value);if(-1===M)return"";let p=f.slice(M).filter(e=>a||0!==e.value).map(e=>t(e.value,e.unit,s,r));return"number"==typeof u&&u>=0&&(p=p.slice(0,u)),p.join(i)}
1
+ import{durationParts as t,findUnit as r}from"./durationParts.js";export function duration(n,o){const{useShortString:u=!1,useSpace:s=!0,separator:a=" "}={...o};return t(n,o).map(t=>function(t,n,o,u){const s=r(n);return`${t}${u?" ":""}${o?s?.short??n:`${n}${1===t?"":"s"}`}`}(t.value,t.unit,u,s)).join(a)}
@@ -0,0 +1,10 @@
1
+ import type { DurationPart, DurationPartsOptions, DurationUnitName } from '../_types/global.js';
2
+ export type Unit = {
3
+ name: DurationUnitName;
4
+ short: string;
5
+ ms: number;
6
+ };
7
+ export declare const UNITS: Unit[];
8
+ export declare function cleanNumber(value: number): number;
9
+ export declare function findUnit(name: string): Unit | undefined;
10
+ export declare function durationParts(milliseconds: number, options?: DurationPartsOptions): DurationPart[];
@@ -0,0 +1 @@
1
+ export const UNITS=[{name:"Year",short:"Y",ms:31536e6},{name:"Month",short:"Mo",ms:2592e6},{name:"Day",short:"D",ms:864e5},{name:"Hour",short:"H",ms:36e5},{name:"Minute",short:"M",ms:6e4},{name:"Second",short:"S",ms:1e3},{name:"Millisecond",short:"ms",ms:1}];export function cleanNumber(e){return Number(e.toFixed(6))}export function findUnit(e){const n=e.toLowerCase().replace(/s$/,"");return UNITS.find(e=>e.name.toLowerCase()===n)}export function durationParts(e,n){const{withZeroValue:t=!1,withMilliSeconds:o=!1,maxUnitCount:r,unit:s}={...n};if(s){const n=findUnit(s);if(n)return[{value:cleanNumber(e/n.ms),unit:n.name}]}const i=o?UNITS:UNITS.filter(e=>"Millisecond"!==e.name),a=[];let m=e;for(const e of i){const n=Math.floor(m/e.ms);m-=n*e.ms,a.push({value:n,unit:e.name})}const u=a.findIndex(e=>0!==e.value);if(-1===u)return[];const c=a.slice(u).filter(e=>t||0!==e.value);return"number"==typeof r&&r>=0?c.slice(0,r):c}
@@ -1,2 +1,2 @@
1
- import type { PositiveNumber } from '../_types/global';
2
- export declare function fileSizeFormat<N extends number>(bytes: PositiveNumber<N>, decimals?: number, ceil?: boolean): string;
1
+ import type { FileSizeOptions, PositiveNumber } from '../_types/global.js';
2
+ export declare function fileSizeFormat<N extends number>(bytes: PositiveNumber<N>, decimals?: number, ceil?: boolean, options?: FileSizeOptions): string;
@@ -1 +1 @@
1
- export function fileSizeFormat(t,o=2,e=!1){const B=["Bytes","KB","MB","GB","TB","PB","EB","ZB","YB"];if(t<1)return`0 ${B[0]}`;const r=Math.floor(Math.log(t)/Math.log(1024)),a=t/1024**r;return`${e?Math.ceil(a):parseFloat(a.toFixed(o<0?0:o))} ${B[r]}`}
1
+ import{fileSizeParts as t,resolveUnitTable as e,unitLabel as i}from"./fileSizeParts.js";export function fileSizeFormat(a,o=2,r=!1,n){const{standard:l,unitDisplay:s}={...n},{value:p,exponent:f}=t(a,n),u=r?Math.ceil(p):parseFloat(p.toFixed(o<0?0:o));return`${u} ${i(e(l),f,s,u)}`}
@@ -0,0 +1,11 @@
1
+ import type { FileSizeOptions, FileSizeParts, FileSizeStandard, PositiveNumber } from '../_types/global.js';
2
+ type UnitTable = {
3
+ base: number;
4
+ short: string[];
5
+ long: string[];
6
+ };
7
+ export declare function resolveUnitTable(standard: FileSizeStandard | undefined): UnitTable;
8
+ export declare function unitLabel(table: UnitTable, exponent: number, unitDisplay: string | undefined, value: number): string;
9
+ export declare function sizeExponent(bytes: number, base: number, unitCount: number): number;
10
+ export declare function fileSizeParts<N extends number>(bytes: PositiveNumber<N>, options?: FileSizeOptions): FileSizeParts;
11
+ export {};
@@ -0,0 +1 @@
1
+ const e={jedec:{base:1024,short:["Bytes","KB","MB","GB","TB","PB","EB","ZB","YB"],long:["Byte","Kilobyte","Megabyte","Gigabyte","Terabyte","Petabyte","Exabyte","Zettabyte","Yottabyte"]},iec:{base:1024,short:["Bytes","KiB","MiB","GiB","TiB","PiB","EiB","ZiB","YiB"],long:["Byte","Kibibyte","Mebibyte","Gibibyte","Tebibyte","Pebibyte","Exbibyte","Zebibyte","Yobibyte"]},si:{base:1e3,short:["Bytes","kB","MB","GB","TB","PB","EB","ZB","YB"],long:["Byte","Kilobyte","Megabyte","Gigabyte","Terabyte","Petabyte","Exabyte","Zettabyte","Yottabyte"]}};export function resolveUnitTable(t){return e[t]??e.jedec}export function unitLabel(e,t,i,b){return"long"!==i?e.short[t]:`${e.long[t]}${1===b?"":"s"}`}export function sizeExponent(e,t,i){return Math.min(Math.floor(Math.log(e)/Math.log(t)),i-1)}export function fileSizeParts(e,t){const{standard:i,unitDisplay:b}={...t},n=resolveUnitTable(i);if(e<1)return{value:0,unit:unitLabel(n,0,b,0),exponent:0};const o=sizeExponent(e,n.base,n.short.length),a=e/n.base**o;return{value:a,unit:unitLabel(n,o,b,a),exponent:o}}
@@ -1,5 +1,7 @@
1
1
  export { duration } from './duration.js';
2
+ export { durationParts } from './durationParts.js';
2
3
  export { fileSizeFormat } from './fileSizeFormat.js';
4
+ export { fileSizeParts } from './fileSizeParts.js';
3
5
  export { numberFormat } from './numberFormat.js';
4
6
  export { safeJSONParse } from './safeJSONParse.js';
5
7
  export { safeParseInt } from './safeParseInt.js';
@@ -1 +1 @@
1
- export{duration}from"./duration.js";export{fileSizeFormat}from"./fileSizeFormat.js";export{numberFormat}from"./numberFormat.js";export{safeJSONParse}from"./safeJSONParse.js";export{safeParseInt}from"./safeParseInt.js";
1
+ export{duration}from"./duration.js";export{durationParts}from"./durationParts.js";export{fileSizeFormat}from"./fileSizeFormat.js";export{fileSizeParts}from"./fileSizeParts.js";export{numberFormat}from"./numberFormat.js";export{safeJSONParse}from"./safeJSONParse.js";export{safeParseInt}from"./safeParseInt.js";
@@ -1 +1 @@
1
- const t=/^\d+$/,n=new Intl.NumberFormat("en-US",{roundingPriority:"morePrecision"});export function numberFormat(r){if(null==r)return"";const e="string"==typeof r?r:r.toString(),o=e.startsWith("-"),i=(o?e.slice(1):e).split("."),s=t.test(i[0])?function(t){let n="";for(let r=t.length;r>0;r-=3){const e=t.slice(Math.max(0,r-3),r);n=""===n?e:`${e},${n}`}return n}(i[0]):n.format(parseInt(i[0],10)),l=`${s}${i.length>1?`.${i[1]}`:""}`;return o?`-${l}`:l}
1
+ const t=/^\d+$/;let n;export function numberFormat(r){if(null==r)return"";const e="string"==typeof r?r:r.toString(),o=e.startsWith("-"),i=(o?e.slice(1):e).split("."),s=t.test(i[0])?function(t){let n="";for(let r=t.length;r>0;r-=3){const e=t.slice(Math.max(0,r-3),r);n=""===n?e:`${e},${n}`}return n}(i[0]):(n??=new Intl.NumberFormat("en-US",{roundingPriority:"morePrecision"})).format(parseInt(i[0],10)),l=`${s}${i.length>1?`.${i[1]}`:""}`;return o?`-${l}`:l}
@@ -1,2 +1,2 @@
1
- import type { AnyValueObject } from '../_types/global';
1
+ import type { AnyValueObject } from '../_types/global.js';
2
2
  export declare function safeJSONParse(jsonString: any, fallback?: {}): AnyValueObject;
@@ -1,2 +1,2 @@
1
- import type { PositiveNumber } from '../_types/global';
1
+ import type { PositiveNumber } from '../_types/global.js';
2
2
  export declare function debounce<N extends number>(func: (...args: any[]) => void, timeout: PositiveNumber<N>): (...args: any[]) => void;
@@ -1,2 +1,2 @@
1
- import type { PositiveNumber } from '../_types/global';
1
+ import type { PositiveNumber } from '../_types/global.js';
2
2
  export declare function funcTimes<N extends number>(times: PositiveNumber<N>, iteratee: any): Array<any>;
@@ -1,2 +1,2 @@
1
- import type { RetryOptions } from '../_types/global';
1
+ import type { RetryOptions } from '../_types/global.js';
2
2
  export declare function retry<T>(func: () => T | Promise<T>, options?: RetryOptions): Promise<T>;
@@ -1,2 +1,2 @@
1
- import type { PositiveNumber } from '../_types/global';
1
+ import type { PositiveNumber } from '../_types/global.js';
2
2
  export declare function sleep<N extends number>(delay: PositiveNumber<N>): Promise<void>;
@@ -1,2 +1,2 @@
1
- import type { PositiveNumber, ThrottleOptions } from '../_types/global';
1
+ import type { PositiveNumber, ThrottleOptions } from '../_types/global.js';
2
2
  export declare function throttle<N extends number>(func: (...args: any[]) => void, wait: PositiveNumber<N>, options?: ThrottleOptions): (...args: any[]) => void;
@@ -1,2 +1,2 @@
1
- import { FileInfo } from '../../_types/global';
1
+ import type { FileInfo } from '../../_types/global.js';
2
2
  export declare function getFileInfo(filePath: string): Promise<FileInfo>;
@@ -1,2 +1,2 @@
1
- import type { HTTPRequestOption } from '../../_types/global';
1
+ import type { HTTPRequestOption } from '../../_types/global.js';
2
2
  export declare function fetchData(url: string, options?: HTTPRequestOption): Promise<any>;
@@ -1,2 +1,2 @@
1
- import { GetUptimeOption } from '../../_types/global';
1
+ import type { GetUptimeOption } from '../../_types/global.js';
2
2
  export declare function getUptime(opt?: GetUptimeOption): number | string;
@@ -1,2 +1,2 @@
1
- import type { AnyValueObject } from '../_types/global';
1
+ import type { AnyValueObject } from '../_types/global.js';
2
2
  export declare function objDeleteKeyByValue(obj: AnyValueObject, searchValue: string | number | null | undefined, recursive?: boolean): AnyValueObject | null;
@@ -1,2 +1,2 @@
1
- import type { AnyValueObject } from '../_types/global';
1
+ import type { AnyValueObject } from '../_types/global.js';
2
2
  export declare function objFindItemRecursiveByKey(obj: AnyValueObject | any[], searchKey: string, searchValue: any, childKey: string): AnyValueObject | null;
@@ -1,4 +1,4 @@
1
- import type { AnyValueObject } from '../_types/global';
1
+ import type { AnyValueObject } from '../_types/global.js';
2
2
  export declare function objGet(obj: AnyValueObject, path: string, options?: {
3
3
  fallback?: any;
4
4
  }): any;
@@ -1,4 +1,4 @@
1
- import type { AnyValueObject } from '../_types/global';
1
+ import type { AnyValueObject } from '../_types/global.js';
2
2
  export declare function objInvert(obj: AnyValueObject): {
3
3
  [key: string]: string;
4
4
  } | null;
@@ -1,2 +1,2 @@
1
- import type { AnyValueObject } from '../_types/global';
1
+ import type { AnyValueObject } from '../_types/global.js';
2
2
  export declare function objMapKeys(obj: AnyValueObject, iteratee: (value: any, key: string) => string): AnyValueObject | null;
@@ -1,2 +1,2 @@
1
- import type { AnyValueObject } from '../_types/global';
1
+ import type { AnyValueObject } from '../_types/global.js';
2
2
  export declare function objMerge(...objects: AnyValueObject[]): AnyValueObject | null;
@@ -1,4 +1,4 @@
1
- import type { AnyValueObject } from '../_types/global';
1
+ import type { AnyValueObject } from '../_types/global.js';
2
2
  export declare function objMergeNewKey(obj: AnyValueObject, obj2: AnyValueObject, options?: {
3
3
  arrayAction?: 'original' | 'replace' | 'append';
4
4
  }): AnyValueObject | null;
@@ -1,2 +1,2 @@
1
- import type { AnyValueObject } from '../_types/global';
1
+ import type { AnyValueObject } from '../_types/global.js';
2
2
  export declare function objPick(obj: AnyValueObject, keys: string | string[]): AnyValueObject | null;
@@ -1,2 +1,2 @@
1
- import type { AnyValueObject } from '../_types/global';
1
+ import type { AnyValueObject } from '../_types/global.js';
2
2
  export declare function objPickBy(obj: AnyValueObject, predicate: (value: any, key: string) => boolean): AnyValueObject | null;
@@ -1,2 +1,2 @@
1
- import type { AnyValueObject } from '../_types/global';
1
+ import type { AnyValueObject } from '../_types/global.js';
2
2
  export declare function objTo1d(obj: AnyValueObject, separator?: string): AnyValueObject;
@@ -1,2 +1,2 @@
1
- import type { AnyValueObject } from '../_types/global';
1
+ import type { AnyValueObject } from '../_types/global.js';
2
2
  export declare function objToArray(obj: AnyValueObject, recursive?: boolean): any[];
@@ -1,2 +1,2 @@
1
- import type { AnyValueObject } from '../_types/global';
1
+ import type { AnyValueObject } from '../_types/global.js';
2
2
  export declare function objToPrettyStr(obj: AnyValueObject): string;
@@ -1,2 +1,2 @@
1
- import type { AnyValueObject } from '../_types/global';
1
+ import type { AnyValueObject } from '../_types/global.js';
2
2
  export declare function objToQueryString(obj: AnyValueObject): string;
@@ -1,2 +1,2 @@
1
- import { AnyValueObject } from '../_types/global';
1
+ import type { AnyValueObject } from '../_types/global.js';
2
2
  export declare function objUpdate(obj: AnyValueObject, key: string, value: any, recursive?: boolean, upsert?: boolean): AnyValueObject | null;
@@ -1 +1 @@
1
- const t=[["ÀÁÂÃÄÅĀĂĄ","A"],["àáâãäåāăą","a"],["ÇĆĈĊČ","C"],["çćĉċč","c"],["ÐĎĐ","D"],["ðďđ","d"],["ÈÉÊËĒĔĖĘĚ","E"],["èéêëēĕėęě","e"],["ĜĞĠĢ","G"],["ĝğġģ","g"],["ĤĦ","H"],["ĥħ","h"],["ÌÍÎÏĨĪĬĮİ","I"],["ìíîïĩīĭįı","i"],["Ĵ","J"],["ĵ","j"],["Ķ","K"],["ķĸ","k"],["ĹĻĽĿŁ","L"],["ĺļľŀł","l"],["ÑŃŅŇŊ","N"],["ñńņňŋ","n"],["ÒÓÔÕÖØŌŎŐ","O"],["òóôõöøōŏő","o"],["ŔŖŘ","R"],["ŕŗř","r"],["ŚŜŞŠ","S"],["śŝşšſ","s"],["ŢŤŦ","T"],["ţťŧ","t"],["ÙÚÛÜŨŪŬŮŰŲ","U"],["ùúûüũūŭůűų","u"],["Ŵ","W"],["ŵ","w"],["ÝŶŸ","Y"],["ýÿŷ","y"],["ŹŻŽ","Z"],["źżž","z"],["Æ","Ae"],["æ","ae"],["Þ","Th"],["þ","th"],["ß","ss"],["IJ","IJ"],["ij","ij"],["Œ","Oe"],["œ","oe"],["ʼn","'n"]],e=new Map;for(let n=0,r=t.length;n<r;n+=1){const[s,c]=t[n];for(const f of s)e.set(f,c)}const o=t=>t>=768&&t<=879||t>=8400&&t<=8432||t>=65056&&t<=65071;export function deburr(t){if(!t)return"";let n="";for(const r of t)o(r.codePointAt(0))||(n+=e.get(r)??r);return n}
1
+ const t=[["ÀÁÂÃÄÅĀĂĄ","A"],["àáâãäåāăą","a"],["ÇĆĈĊČ","C"],["çćĉċč","c"],["ÐĎĐ","D"],["ðďđ","d"],["ÈÉÊËĒĔĖĘĚ","E"],["èéêëēĕėęě","e"],["ĜĞĠĢ","G"],["ĝğġģ","g"],["ĤĦ","H"],["ĥħ","h"],["ÌÍÎÏĨĪĬĮİ","I"],["ìíîïĩīĭįı","i"],["Ĵ","J"],["ĵ","j"],["Ķ","K"],["ķĸ","k"],["ĹĻĽĿŁ","L"],["ĺļľŀł","l"],["ÑŃŅŇŊ","N"],["ñńņňŋ","n"],["ÒÓÔÕÖØŌŎŐ","O"],["òóôõöøōŏő","o"],["ŔŖŘ","R"],["ŕŗř","r"],["ŚŜŞŠ","S"],["śŝşšſ","s"],["ŢŤŦ","T"],["ţťŧ","t"],["ÙÚÛÜŨŪŬŮŰŲ","U"],["ùúûüũūŭůűų","u"],["Ŵ","W"],["ŵ","w"],["ÝŶŸ","Y"],["ýÿŷ","y"],["ŹŻŽ","Z"],["źżž","z"],["Æ","Ae"],["æ","ae"],["Þ","Th"],["þ","th"],["ß","ss"],["IJ","IJ"],["ij","ij"],["Œ","Oe"],["œ","oe"],["ʼn","'n"]];let e;const o=t=>t>=768&&t<=879||t>=8400&&t<=8432||t>=65056&&t<=65071;export function deburr(n){if(!n)return"";const r=(()=>{if(void 0!==e)return e;e=new Map;for(let o=0,n=t.length;o<n;o+=1){const[n,r]=t[o];for(const t of n)e.set(t,r)}return e})();let s="";for(const t of n)o(t.codePointAt(0))||(s+=r.get(t)??t);return s}
@@ -1,2 +1,2 @@
1
- import type { PadOptions } from '../_types/global';
1
+ import type { PadOptions } from '../_types/global.js';
2
2
  export declare function pad(str: string, length: number, options?: PadOptions): string;
@@ -1,2 +1,2 @@
1
- import type { PositiveNumber } from '../_types/global';
1
+ import type { PositiveNumber } from '../_types/global.js';
2
2
  export declare function strBlindRandom<N extends number>(str: string, blindLength: PositiveNumber<N>, blindStr?: string): string;
@@ -1,2 +1,2 @@
1
- import type { PositiveNumber } from '../_types/global';
1
+ import type { PositiveNumber } from '../_types/global.js';
2
2
  export declare function strRandom<N extends number>(length: PositiveNumber<N>, additionalCharacters?: string): string;
@@ -1,2 +1,2 @@
1
- import type { PositiveNumber } from '../_types/global';
1
+ import type { PositiveNumber } from '../_types/global.js';
2
2
  export declare function truncate<N extends number>(str: string, length: PositiveNumber<N>, ellipsis?: string): string;
@@ -1 +1 @@
1
- export function truncate(t,n,r=""){if(!t)return"";let e=t;return t.length>n&&(e=t.substring(0,n)+r),e}
1
+ export function truncate(r,n,t=""){if(!r)return"";const e=Array.from(r);return e.length<=n?r:e.slice(0,n).join("")+t}
@@ -1,2 +1,2 @@
1
- import type { PositiveNumber } from '../_types/global';
2
- export declare function truncateExpect<N extends number>(str: string, expectLength: PositiveNumber<N>, endStringChar?: string): string;
1
+ import type { PositiveNumber } from '../_types/global.js';
2
+ export declare function truncateExpect<N extends number>(str: string, expectLength: PositiveNumber<N>, endStringChar?: string | string[]): string;
@@ -1 +1 @@
1
- export function truncateExpect(t,e,n="."){if(!t)return"";if(t.length<=e)return t;const r=t.slice(-1)===n,l=t.split(n),c=l.length;let i="",u=0;for(let t=0;t<c&&u<e;t+=1)i+=`${l[t]}${t!==c-1||r?n:""}`,u+=l[t].length+n.length;return i}
1
+ const r=[".","。",".","。"];function t(r,t,n){if(n+t.length>r.length)return!1;for(let e=0;e<t.length;e+=1)if(r[n+e]!==t[e])return!1;return!0}export function truncateExpect(n,e,f=r){if(!n)return"";const i=Array.from(n),l=i.length;if(l<=e)return n;const o=(Array.isArray(f)?f:[f]).filter(r=>r.length>0).map(r=>Array.from(r)).sort((r,t)=>t.length-r.length);if(0===o.length)return n;let u=0;for(;u<l;){const r=o.find(r=>t(i,r,u));if(r){if(u+=r.length,u>=e)return i.slice(0,u).join("")}else u+=1}return n}
@@ -1 +1 @@
1
- const o="ㄱㄲㄴㄷㄸㄹㅁㅂㅃㅅㅆㅇㅈㅉㅊㅋㅌㅍㅎ",t="ㅏㅐㅑㅒㅓㅔㅕㅖㅗㅘㅙㅚㅛㅜㅝㅞㅟㅠㅡㅢㅣ",n=" ㄱㄲㄳㄴㄵㄶㄷㄹㄺㄻㄼㄽㄾㄿㅀㅁㅂㅄㅅㅆㅇㅈㅊㅋㅌㅍㅎ",e={"ㅗㅏ":"ㅘ","ㅗㅐ":"ㅙ","ㅗㅣ":"ㅚ","ㅜㅓ":"ㅝ","ㅜㅔ":"ㅞ","ㅜㅣ":"ㅟ","ㅡㅣ":"ㅢ"},r={"ㄱㅅ":"ㄳ","ㄴㅈ":"ㄵ","ㄴㅎ":"ㄶ","ㄹㄱ":"ㄺ","ㄹㅁ":"ㄻ","ㄹㅂ":"ㄼ","ㄹㅅ":"ㄽ","ㄹㅌ":"ㄾ","ㄹㅍ":"ㄿ","ㄹㅎ":"ㅀ","ㅂㅅ":"ㅄ"},s={r:"ㅏ",i:"ㅣ"},f=o=>{const t={};for(const n of o)for(const o of n.slice(1))t[o]=n[0];return t},i=[9398,119808,119860,119912,120224,120276,120328,120380,120432],c=o=>{for(const t of i)if(o>=t&&o<=t+51)return String.fromCharCode(97+(o-t)%26)},l=f(["a4àáâãäåāăąаα","b8вβ","cçćčс","dďđ","e3èéêëēĕėęěеёε","g69ğ","hн","i1lìíîïīįıłіι","jј","kкκ","mм","nñńň","o0òóôõöøōőоο","pрρ","s5śšşѕ","t7ţťтτ","uùúûüūůűų","xхχ","yýÿу","z2źżž"]),u=f(["a@","c¢(","e€£","i!|¡/","s$§","t+","o°"]),h=/[\p{L}\p{N}]/u,d=o=>void 0!==o&&(t.includes(o)||void 0!==s[o]),p=(f,i,p)=>{const g=[],a=[];for(const e of f.toLowerCase()){let r=e;const s=r.codePointAt(0);s>=65281&&s<=65374?r=String.fromCharCode(s-65248).toLowerCase():s>=4352&&s<=4370?r=o[s-4352]:s>=4449&&s<=4469?r=t[s-4449]:s>=4520&&s<=4546?r=n[s-4519]:s>=9398&&(r=c(s)??r);const f=r>="0"&&r<="9";void 0!==l[r]?(g.push(l[r]),a.push(f)):h.test(r)?(g.push(r),a.push(f)):i&&void 0!==u[r]&&(g.push(u[r]),a.push(!1))}const x=p?((o,t)=>{const n=[],e=o.length;let r=0;for(;r<e;){if(!t[r]){n.push(o[r]),r+=1;continue}let s=r;for(;s<e&&t[s];)s+=1;if(0===r||s===e)for(let t=r;t<s;t+=1)n.push(o[t]);r=s}return n})(g,a):g;for(let o=1,t=x.length;o<t;o+=1)"ㅇ"===x[o]&&x[o-1]>="a"&&x[o-1]<="z"&&(x[o]="o");return(f=>{const i=[],c=f.length;let l=0;for(;l<c;){const u=o.indexOf(f[l]);let h=l+1,p=h<c?t.indexOf(s[f[h]]??f[h]):-1;if(-1===u||-1===p){i.push(f[l]),l+=1;continue}h+=1;const g=h<c?e[t[p]+f[h]]:void 0;void 0!==g&&(p=t.indexOf(g),h+=1);let a=h<c&&!d(f[h+1])?Math.max(n.indexOf(f[h]),0):0;if(a>0){h+=1;const o=h<c?r[n[a]+f[h]]:void 0;void 0===o||d(f[h+1])||(a=n.indexOf(o),h+=1)}i.push(String.fromCharCode(44032+28*(21*u+p)+a)),l=h}return i.join("")})(x).replace(/ㅇ/g,"o")},g=(o,t,n,e)=>{for(let r=0,s=n.length;r<s;r+=1)if(o>=n[r]&&o<e[r])return o===n[r]||o+t<=e[r];return!1},a=[[!0,!1],[!1,!1],[!0,!0],[!1,!0]],x=o=>{const t=[];for(const n of o){if("string"!=typeof n)continue;const o=p(n,!0,!1);o&&t.push(o)}return t};export function hasBadWords(o,t=[],n=[]){if(!o||!t||0===t.length)return!1;const e=x(t);if(0===e.length)return!1;const r=n?x(n):[],s=o.split(/\s+/).filter(o=>""!==o);for(const[o,t]of a){const n=[],f=[];let i="";for(const e of s){const r=p(e,o,t);r&&(n.push(i.length),i+=r,f.push(i.length))}for(const o of r){let t=i.indexOf(o);for(;-1!==t;)i=i.slice(0,t)+"\0".repeat(o.length)+i.slice(t+o.length),t=i.indexOf(o,t+o.length)}for(const o of e){let t=i.indexOf(o);for(;-1!==t;){if(g(t,o.length,n,f))return!0;t=i.indexOf(o,t+1)}}}return!1}
1
+ const t="ㄱㄲㄴㄷㄸㄹㅁㅂㅃㅅㅆㅇㅈㅉㅊㅋㅌㅍㅎ",o="ㅏㅐㅑㅒㅓㅔㅕㅖㅗㅘㅙㅚㅛㅜㅝㅞㅟㅠㅡㅢㅣ",n=" ㄱㄲㄳㄴㄵㄶㄷㄹㄺㄻㄼㄽㄾㄿㅀㅁㅂㅄㅅㅆㅇㅈㅊㅋㅌㅍㅎ",e={"ㅗㅏ":"ㅘ","ㅗㅐ":"ㅙ","ㅗㅣ":"ㅚ","ㅜㅓ":"ㅝ","ㅜㅔ":"ㅞ","ㅜㅣ":"ㅟ","ㅡㅣ":"ㅢ"},r={"ㄱㅅ":"ㄳ","ㄴㅈ":"ㄵ","ㄴㅎ":"ㄶ","ㄹㄱ":"ㄺ","ㄹㅁ":"ㄻ","ㄹㅂ":"ㄼ","ㄹㅅ":"ㄽ","ㄹㅌ":"ㄾ","ㄹㅍ":"ㄿ","ㄹㅎ":"ㅀ","ㅂㅅ":"ㅄ"},s={r:"ㅏ",i:"ㅣ"},f=["a4àáâãäåāăąаα","b8вβ","cçćčс","dďđ","e3èéêëēĕėęěеёε","g69ğ","hн","i1lìíîïīįıłіι","jј","kкκ","mм","nñńň","o0òóôõöøōőоο","pрρ","s5śšşѕ","t7ţťтτ","uùúûüūůűų","xхχ","yýÿу","z2źżž"],i=["a@","c¢(","e€£","i!|¡/","s$§","t+","o°"],c=t=>{const o={};for(const n of t)for(const t of n.slice(1))o[t]=n[0];return o},l=[9398,119808,119860,119912,120224,120276,120328,120380,120432],u=t=>{for(const o of l)if(t>=o&&t<=o+51)return String.fromCharCode(97+(t-o)%26)};let h,d;const p=/[\p{L}\p{N}]/u,g=t=>void 0!==t&&(o.includes(t)||void 0!==s[t]),a=(l,a,x)=>{const O=h??=c(f),v=d??=c(i),C=[],m=[];for(const e of l.toLowerCase()){let r=e;const s=r.codePointAt(0);s>=65281&&s<=65374?r=String.fromCharCode(s-65248).toLowerCase():s>=4352&&s<=4370?r=t[s-4352]:s>=4449&&s<=4469?r=o[s-4449]:s>=4520&&s<=4546?r=n[s-4519]:s>=9398&&(r=u(s)??r);const f=r>="0"&&r<="9";void 0!==O[r]?(C.push(O[r]),m.push(f)):p.test(r)?(C.push(r),m.push(f)):a&&void 0!==v[r]&&(C.push(v[r]),m.push(!1))}const L=x?((t,o)=>{const n=[],e=t.length;let r=0;for(;r<e;){if(!o[r]){n.push(t[r]),r+=1;continue}let s=r;for(;s<e&&o[s];)s+=1;if(0===r||s===e)for(let o=r;o<s;o+=1)n.push(t[o]);r=s}return n})(C,m):C;for(let t=1,o=L.length;t<o;t+=1)"ㅇ"===L[t]&&L[t-1]>="a"&&L[t-1]<="z"&&(L[t]="o");return(f=>{const i=[],c=f.length;let l=0;for(;l<c;){const u=t.indexOf(f[l]);let h=l+1,d=h<c?o.indexOf(s[f[h]]??f[h]):-1;if(-1===u||-1===d){i.push(f[l]),l+=1;continue}h+=1;const p=h<c?e[o[d]+f[h]]:void 0;void 0!==p&&(d=o.indexOf(p),h+=1);let a=h<c&&!g(f[h+1])?Math.max(n.indexOf(f[h]),0):0;if(a>0){h+=1;const t=h<c?r[n[a]+f[h]]:void 0;void 0===t||g(f[h+1])||(a=n.indexOf(t),h+=1)}i.push(String.fromCharCode(44032+28*(21*u+d)+a)),l=h}return i.join("")})(L).replace(/ㅇ/g,"o")},x=(t,o,n,e)=>{for(let r=0,s=n.length;r<s;r+=1)if(t>=n[r]&&t<e[r])return t===n[r]||t+o<=e[r];return!1},O=[[!0,!1],[!1,!1],[!0,!0],[!1,!0]],v=t=>{const o=[];for(const n of t){if("string"!=typeof n)continue;const t=a(n,!0,!1);t&&o.push(t)}return o};export function hasBadWords(t,o=[],n=[]){if(!t||!o||0===o.length)return!1;const e=v(o);if(0===e.length)return!1;const r=n?v(n):[],s=t.split(/\s+/).filter(t=>""!==t);for(const[t,o]of O){const n=[],f=[];let i="";for(const e of s){const r=a(e,t,o);r&&(n.push(i.length),i+=r,f.push(i.length))}for(const t of r){let o=i.indexOf(t);for(;-1!==o;)i=i.slice(0,o)+"\0".repeat(t.length)+i.slice(o+t.length),o=i.indexOf(t,o+t.length)}for(const t of e){let o=i.indexOf(t);for(;-1!==o;){if(x(o,t.length,n,f))return!0;o=i.indexOf(t,o+1)}}}return!1}
@@ -1,2 +1,2 @@
1
- import { LicenseOption } from '../_types/global';
1
+ import type { LicenseOption } from '../_types/global.js';
2
2
  export declare function generateLicense(options: LicenseOption): string;
@@ -1,2 +1,2 @@
1
- import type { ParsedAddress } from '../_types/global';
1
+ import type { ParsedAddress } from '../_types/global.js';
2
2
  export declare function getParsedInfoFromAddress(url: string): ParsedAddress;
@@ -1,2 +1,2 @@
1
- import type { SlugOptions } from '../_types/global';
1
+ import type { SlugOptions } from '../_types/global.js';
2
2
  export declare function getSlug(text: string, options?: SlugOptions): string;
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "qsu",
3
- "version": "1.17.0",
4
- "description": "qsu is a utility library that contains useful and frequently used functions. Start with your preferred language and the modern development environment.",
5
- "author": "CDGet <jooy2.contact@gmail.com>",
3
+ "version": "1.19.0",
4
+ "description": "Everyday helpers you would otherwise write yourself: slugs, text case, date math, number and file size formatting, deep clone and merge, email and URL validation, debounce, throttle and hashing. No dependencies.",
5
+ "author": "CDGet (https://cdget.com)",
6
6
  "license": "MIT",
7
7
  "homepage": "https://qsu.cdget.com",
8
8
  "repository": {
@@ -13,6 +13,7 @@
13
13
  "url": "https://github.com/jooy2/qsu/issues"
14
14
  },
15
15
  "type": "module",
16
+ "sideEffects": false,
16
17
  "types": "dist/index.d.ts",
17
18
  "scripts": {
18
19
  "build": "tsc --project tsconfig.prod.json && npm run minify",
@@ -21,8 +22,7 @@
21
22
  "lint:fix": "eslint . --ext .js,.ts --fix .",
22
23
  "minify": "terser-glob 'dist/**/*.js' --config-file terser.config.json",
23
24
  "prepare": "npm run build",
24
- "format": "prettier .",
25
- "format:fix": "prettier . --write"
25
+ "format": "prettier . --write"
26
26
  },
27
27
  "engines": {
28
28
  "node": ">=18.0.0"
@@ -35,15 +35,86 @@
35
35
  "default": "./dist/index.js"
36
36
  },
37
37
  "./types": {
38
- "types": "./dist/types/global.d.ts",
39
- "module": "./dist/types/global.js",
40
- "default": "./dist/types/global.js"
38
+ "types": "./dist/_types/global.d.ts",
39
+ "module": "./dist/_types/global.js",
40
+ "default": "./dist/_types/global.js"
41
+ },
42
+ "./array": {
43
+ "types": "./dist/array/index.d.ts",
44
+ "module": "./dist/array/index.js",
45
+ "default": "./dist/array/index.js"
46
+ },
47
+ "./date": {
48
+ "types": "./dist/date/index.d.ts",
49
+ "module": "./dist/date/index.js",
50
+ "default": "./dist/date/index.js"
51
+ },
52
+ "./format": {
53
+ "types": "./dist/format/index.d.ts",
54
+ "module": "./dist/format/index.js",
55
+ "default": "./dist/format/index.js"
56
+ },
57
+ "./math": {
58
+ "types": "./dist/math/index.d.ts",
59
+ "module": "./dist/math/index.js",
60
+ "default": "./dist/math/index.js"
61
+ },
62
+ "./misc": {
63
+ "types": "./dist/misc/index.d.ts",
64
+ "module": "./dist/misc/index.js",
65
+ "default": "./dist/misc/index.js"
66
+ },
67
+ "./object": {
68
+ "types": "./dist/object/index.d.ts",
69
+ "module": "./dist/object/index.js",
70
+ "default": "./dist/object/index.js"
71
+ },
72
+ "./string": {
73
+ "types": "./dist/string/index.d.ts",
74
+ "module": "./dist/string/index.js",
75
+ "default": "./dist/string/index.js"
76
+ },
77
+ "./verify": {
78
+ "types": "./dist/verify/index.d.ts",
79
+ "module": "./dist/verify/index.js",
80
+ "default": "./dist/verify/index.js"
81
+ },
82
+ "./web": {
83
+ "types": "./dist/web/index.d.ts",
84
+ "module": "./dist/web/index.js",
85
+ "default": "./dist/web/index.js"
41
86
  },
42
87
  "./node": {
43
88
  "types": "./dist/node/index.d.ts",
44
89
  "module": "./dist/node/index.js",
45
90
  "default": "./dist/node/index.js"
46
- }
91
+ },
92
+ "./node/crypto": {
93
+ "types": "./dist/node/crypto/index.d.ts",
94
+ "module": "./dist/node/crypto/index.js",
95
+ "default": "./dist/node/crypto/index.js"
96
+ },
97
+ "./node/file": {
98
+ "types": "./dist/node/file/index.d.ts",
99
+ "module": "./dist/node/file/index.js",
100
+ "default": "./dist/node/file/index.js"
101
+ },
102
+ "./node/misc": {
103
+ "types": "./dist/node/misc/index.d.ts",
104
+ "module": "./dist/node/misc/index.js",
105
+ "default": "./dist/node/misc/index.js"
106
+ },
107
+ "./node/net": {
108
+ "types": "./dist/node/net/index.d.ts",
109
+ "module": "./dist/node/net/index.js",
110
+ "default": "./dist/node/net/index.js"
111
+ },
112
+ "./node/os": {
113
+ "types": "./dist/node/os/index.d.ts",
114
+ "module": "./dist/node/os/index.js",
115
+ "default": "./dist/node/os/index.js"
116
+ },
117
+ "./package.json": "./package.json"
47
118
  },
48
119
  "typesVersions": {
49
120
  "*": {
@@ -55,36 +126,48 @@
55
126
  "keywords": [
56
127
  "util",
57
128
  "utility",
58
- "tool",
129
+ "utils",
59
130
  "toolkit",
60
- "underscore",
61
- "web",
62
131
  "helper",
132
+ "lodash",
133
+ "underscore",
134
+ "typescript",
135
+ "esm",
136
+ "tree-shaking",
137
+ "zero-dependency",
63
138
  "array",
139
+ "object",
64
140
  "string",
65
141
  "date",
66
142
  "math",
143
+ "format",
144
+ "validation",
67
145
  "verify",
146
+ "crypto",
147
+ "hash",
68
148
  "encrypt",
69
149
  "decrypt",
70
- "format",
71
- "crypto",
72
- "file"
150
+ "base64",
151
+ "file",
152
+ "web",
153
+ "slug",
154
+ "debounce",
155
+ "throttle"
73
156
  ],
74
157
  "devDependencies": {
75
158
  "@eslint/js": "^9.39.2",
76
- "@types/node": "^26.1.2",
77
- "@typescript-eslint/parser": "^8.66.0",
78
- "dayjs": "^1.11.21",
159
+ "@types/node": "^26.4.0",
160
+ "@typescript-eslint/parser": "^8.68.0",
161
+ "dayjs": "^1.11.23",
79
162
  "eslint": "^9.39.2",
80
163
  "eslint-config-prettier": "^10.1.8",
81
- "eslint-plugin-n": "^18.2.2",
82
- "globals": "^17.9.0",
164
+ "eslint-plugin-n": "^18.3.0",
165
+ "globals": "^17.11.0",
83
166
  "jiti": "^2.7.0",
84
167
  "prettier": "^3.9.6",
85
168
  "terser-glob": "^1.2.1",
86
- "tsx": "^4.23.9",
169
+ "tsx": "^4.23.12",
87
170
  "typescript": "6.0.3",
88
- "typescript-eslint": "^8.66.0"
171
+ "typescript-eslint": "^8.68.0"
89
172
  }
90
173
  }