imagic-utils 1.0.1 → 2.1.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/README.md CHANGED
@@ -1 +1,262 @@
1
- # utils
1
+ # imagic-utils
2
+
3
+ > Collection of general-purpose utility functions for arrays, numbers, strings, random values, IDs, hashing, and async helpers.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install imagic-utils
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```js
14
+ import { getRandInteger, getRandString, generateId, wait } from 'imagic-utils'
15
+
16
+ const id = generateId() // '3f2a1b4c...' (32 hex chars)
17
+ const n = getRandInteger(1, 100) // e.g. 42
18
+ const s = getRandString(8) // e.g. 'aX9kPq2Z'
19
+
20
+ await wait(500) // pause for 500 ms
21
+ ```
22
+
23
+ ## API
24
+
25
+ ### Arrays
26
+
27
+ #### `getRandArrayItem(array)` → `any`
28
+
29
+ Returns a random element from the array. Returns `undefined` if the array is empty.
30
+
31
+ ```ts
32
+ getRandArrayItem(array: any[]): any
33
+ ```
34
+
35
+ - `array` — must be an `Array`; throws `TypeError` if not
36
+
37
+ Alias: `getRandomArrayItem`
38
+
39
+ ---
40
+
41
+ #### `chunkArray(array, chunkSize)` → `any[][]`
42
+
43
+ Splits an array into sub-arrays of the given size. The last chunk may be smaller than `chunkSize`.
44
+
45
+ ```ts
46
+ chunkArray(array: any[], chunkSize: number): any[][]
47
+ ```
48
+
49
+ - `array` — must be an `Array`; throws `TypeError` if not
50
+ - `chunkSize` — must be a positive integer; throws if not
51
+
52
+ ---
53
+
54
+ #### `shuffle(variable)` → `any[]`
55
+
56
+ Returns a **new** array with elements in random order (Fisher-Yates algorithm). Does not mutate the original.
57
+
58
+ ```ts
59
+ shuffle(variable: any[]): any[]
60
+ ```
61
+
62
+ - `variable` — must be an `Array`; throws `TypeError` if not
63
+
64
+ ---
65
+
66
+ ### Numbers
67
+
68
+ #### `getRandInteger(min, max)` → `number`
69
+
70
+ Returns a random integer in the inclusive range `[min, max]`.
71
+
72
+ ```ts
73
+ getRandInteger(min: number, max: number): number
74
+ ```
75
+
76
+ - `min`, `max` — must be finite numbers; throws `TypeError` if not
77
+ - Throws `RangeError` if there is no integer in `[min, max]`
78
+
79
+ Alias: `getRandomInteger`
80
+
81
+ ---
82
+
83
+ #### `getRandFloat(min, max, decimalPoint?)` → `number`
84
+
85
+ Returns a random floating-point number in `[min, max]`, rounded to `decimalPoint` decimal places.
86
+
87
+ ```ts
88
+ getRandFloat(min: number, max: number, decimalPoint?: number): number
89
+ ```
90
+
91
+ - `min`, `max` — numeric bounds
92
+ - `decimalPoint` — integer `0–15`; default `5`; throws `RangeError` if outside that range
93
+
94
+ Alias: `getRandomFloat`
95
+
96
+ ---
97
+
98
+ #### `chance(percent)` → `boolean`
99
+
100
+ Returns `true` with `percent`% probability.
101
+
102
+ ```ts
103
+ chance(percent: number): boolean
104
+ ```
105
+
106
+ - `0` always returns `false`; `100` always returns `true`
107
+ - Throws `TypeError` if `percent` is not a finite number
108
+
109
+ ---
110
+
111
+ ### Strings
112
+
113
+ #### `getRandString(length?, charSet?)` → `string`
114
+
115
+ Returns a random string composed of characters from `charSet`.
116
+
117
+ ```ts
118
+ getRandString(length?: number, charSet?: string): string
119
+ ```
120
+
121
+ - `length` — default `16`
122
+ - `charSet` — default `A-Za-z0-9` (62 characters); throws if an empty string is provided
123
+
124
+ Alias: `getRandomString`
125
+
126
+ ---
127
+
128
+ #### `isJSON(json)` → `boolean`
129
+
130
+ Returns `true` if the argument is a string containing valid JSON; `false` for any other input (including non-strings).
131
+
132
+ ```ts
133
+ isJSON(json: any): boolean
134
+ ```
135
+
136
+ ---
137
+
138
+ ### Random Bytes / IDs
139
+
140
+ #### `getRandomBytes(length)` → `Uint8Array`
141
+
142
+ Returns cryptographically random bytes. Uses `crypto.getRandomValues` when available (browser / Node.js ≥ 15), otherwise falls back to `node:crypto`.
143
+
144
+ ```ts
145
+ getRandomBytes(length: number): Uint8Array
146
+ ```
147
+
148
+ - `length` — must be a positive integer; throws `TypeError` if not
149
+
150
+ ---
151
+
152
+ #### `generateId()` → `string`
153
+
154
+ Returns a 32-character lowercase hex string generated from 16 random bytes.
155
+
156
+ ```ts
157
+ generateId(): string
158
+ ```
159
+
160
+ Alias: `generateHexId`
161
+
162
+ ---
163
+
164
+ #### `generateBigId()` → `string`
165
+
166
+ Returns a UUIDv4-formatted string (`xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx`).
167
+
168
+ ```ts
169
+ generateBigId(): string
170
+ ```
171
+
172
+ Alias: `generateUuidV4`
173
+
174
+ ---
175
+
176
+ #### `md5(data)` → `string`
177
+
178
+ Returns the 32-character lowercase hex MD5 hash of the input.
179
+
180
+ ```ts
181
+ md5(data: string | Buffer | Uint8Array): string
182
+ ```
183
+
184
+ ---
185
+
186
+ ### Promises
187
+
188
+ #### `wait(milliseconds)` → `Promise<void>`
189
+
190
+ Resolves after the given number of milliseconds.
191
+
192
+ ```ts
193
+ wait(milliseconds: number): Promise<void>
194
+ ```
195
+
196
+ - `milliseconds` — must be a non-negative number; throws `TypeError` if not
197
+
198
+ ---
199
+
200
+ ### Node.js-only
201
+
202
+ The following exports are available in `src/index.js` but **not** in `src/browser.js`. Calling the browser stubs throws an explicit error.
203
+
204
+ #### `getLocalAddress()` → `string`
205
+
206
+ Returns the first non-loopback IPv4 address of the current machine.
207
+
208
+ #### `getLocalAddresses()` → `string[]`
209
+
210
+ Returns all non-loopback IPv4 addresses of the current machine.
211
+
212
+ #### `getCPUUsage()` → `number`
213
+
214
+ Returns the current CPU usage as a percentage in the range `0–100`.
215
+
216
+ ---
217
+
218
+ ### Aliases
219
+
220
+ | Alias | Canonical name |
221
+ |-------|---------------|
222
+ | `getRandomArrayItem` | `getRandArrayItem` |
223
+ | `getRandomFloat` | `getRandFloat` |
224
+ | `getRandomInteger` | `getRandInteger` |
225
+ | `getRandomString` | `getRandString` |
226
+ | `generateUuidV4` | `generateBigId` |
227
+ | `generateHexId` | `generateId` |
228
+
229
+ ---
230
+
231
+ ## Error Handling
232
+
233
+ | Function | Error type | Condition |
234
+ |----------|-----------|-----------|
235
+ | `getRandArrayItem` | `TypeError` | argument is not an Array |
236
+ | `chunkArray` | `TypeError` | `array` is not an Array |
237
+ | `chunkArray` | `TypeError` / `RangeError` | `chunkSize` is not a positive integer |
238
+ | `shuffle` | `TypeError` | argument is not an Array |
239
+ | `getRandInteger` | `TypeError` | `min` or `max` is not a finite number |
240
+ | `getRandInteger` | `RangeError` | no integer exists in `[min, max]` |
241
+ | `getRandFloat` | `RangeError` | `decimalPoint` is outside `0–15` |
242
+ | `chance` | `TypeError` | `percent` is not a finite number |
243
+ | `getRandString` | `Error` | `charSet` is an empty string |
244
+ | `getRandomBytes` | `TypeError` | `length` is not a positive integer |
245
+ | `wait` | `TypeError` | `milliseconds` is not a non-negative number |
246
+ | Node-only in browser | `Error` | called in a browser environment |
247
+
248
+ ---
249
+
250
+ ## Examples
251
+
252
+ See the [`examples/`](./examples/) directory for runnable scripts:
253
+
254
+ ```bash
255
+ node examples/basic.js
256
+ ```
257
+
258
+ ---
259
+
260
+ ## License
261
+
262
+ MIT © iMagicKey
package/package.json CHANGED
@@ -1,11 +1,29 @@
1
1
  {
2
2
  "name": "imagic-utils",
3
- "version": "1.0.1",
4
- "description": "Utils package",
5
- "main": "src/index.js",
3
+ "version": "2.1.1",
4
+ "description": "Provide random, hashing, array, string, and OS utility helpers for Node.js and browsers",
5
+ "exports": {
6
+ ".": {
7
+ "browser": "./src/browser.js",
8
+ "default": "./src/index.js"
9
+ },
10
+ "./browser": "./src/browser.js",
11
+ "./node": "./src/index.js",
12
+ "./package.json": "./package.json"
13
+ },
14
+ "sideEffects": false,
15
+ "files": [
16
+ "src",
17
+ "README.md",
18
+ "LICENSE"
19
+ ],
6
20
  "type": "module",
7
21
  "scripts": {
8
- "test": "node ./tests/index.js"
22
+ "test": "node --test ./tests/**/*.test.js",
23
+ "lint": "eslint src",
24
+ "lint:fix": "eslint src --fix",
25
+ "deps:check": "npm outdated",
26
+ "deps:update": "npm update"
9
27
  },
10
28
  "repository": {
11
29
  "type": "git",
@@ -22,6 +40,18 @@
22
40
  },
23
41
  "homepage": "https://github.com/iMagicKey/utils#readme",
24
42
  "engines": {
25
- "node": ">=18"
43
+ "node": ">=24"
44
+ },
45
+ "devDependencies": {
46
+ "@eslint/js": "latest",
47
+ "chai": "latest",
48
+ "eslint": "latest",
49
+ "eslint-config-prettier": "latest",
50
+ "eslint-plugin-import": "latest",
51
+ "eslint-plugin-n": "latest",
52
+ "eslint-plugin-prettier": "latest",
53
+ "eslint-plugin-promise": "latest",
54
+ "globals": "latest",
55
+ "prettier": "latest"
26
56
  }
27
57
  }
package/src/browser.js ADDED
@@ -0,0 +1,28 @@
1
+ import sharedUtils from './shared.js'
2
+
3
+ export * from './shared.js'
4
+
5
+ function createUnsupportedFunction(name) {
6
+ return function unsupportedInBrowser() {
7
+ throw new Error(`${name} is available only in Node.js environments`)
8
+ }
9
+ }
10
+
11
+ const getLocalAddress = createUnsupportedFunction('getLocalAddress')
12
+ const getLocalAddresses = createUnsupportedFunction('getLocalAddresses')
13
+ const getCPUUsage = createUnsupportedFunction('getCPUUsage')
14
+ const getLocalIPv4Address = getLocalAddress
15
+ const getLocalIPv4Addresses = getLocalAddresses
16
+
17
+ const browserUtils = {
18
+ ...sharedUtils,
19
+ getLocalAddress,
20
+ getLocalAddresses,
21
+ getCPUUsage,
22
+ getLocalIPv4Address,
23
+ getLocalIPv4Addresses,
24
+ }
25
+
26
+ export { getLocalAddress, getLocalAddresses, getCPUUsage, getLocalIPv4Address, getLocalIPv4Addresses }
27
+
28
+ export default browserUtils
package/src/index.js CHANGED
@@ -1,33 +1,22 @@
1
- import getRandArrayItem from './utils/array/getRandArrayItem.js'
2
- import chunkArray from './utils/array/chunkArray.js'
3
- import getRandFloat from './utils/float/getRandFloat.js'
4
- import chance from './utils/general/chance.js'
5
- import generateBigId from './utils/general/generateBigId.js'
6
- import generateId from './utils/general/generateId.js'
7
- import isJSON from './utils/general/isJSON.js'
8
- import shuffle from './utils/general/shuffle.js'
9
- import wait from './utils/general/wait.js'
10
- import md5 from './utils/general/md5.js'
11
- import getRandInteger from './utils/integer/getRandInteger.js'
1
+ import sharedUtils from './shared.js'
12
2
  import getLocalAddress from './utils/os/getLocalAddress.js'
13
3
  import getLocalAddresses from './utils/os/getLocalAddresses.js'
14
4
  import getCPUUsage from './utils/os/getCPUUsage.js'
15
- import getRandString from './utils/string/getRandString.js'
16
5
 
17
- export default {
18
- getRandArrayItem,
19
- chunkArray,
20
- getRandFloat,
21
- chance,
22
- generateBigId,
23
- generateId,
24
- isJSON,
25
- shuffle,
26
- wait,
27
- md5,
28
- getRandInteger,
6
+ export * from './shared.js'
7
+
8
+ const getLocalIPv4Address = getLocalAddress
9
+ const getLocalIPv4Addresses = getLocalAddresses
10
+
11
+ const nodeUtils = {
12
+ ...sharedUtils,
29
13
  getLocalAddress,
30
14
  getLocalAddresses,
31
15
  getCPUUsage,
32
- getRandString,
16
+ getLocalIPv4Address,
17
+ getLocalIPv4Addresses,
33
18
  }
19
+
20
+ export { getLocalAddress, getLocalAddresses, getCPUUsage, getLocalIPv4Address, getLocalIPv4Addresses }
21
+
22
+ export default nodeUtils
package/src/shared.js ADDED
@@ -0,0 +1,66 @@
1
+ import getRandArrayItem from './utils/array/getRandArrayItem.js'
2
+ import chunkArray from './utils/array/chunkArray.js'
3
+ import getRandFloat from './utils/float/getRandFloat.js'
4
+ import chance from './utils/general/chance.js'
5
+ import generateBigId from './utils/general/generateBigId.js'
6
+ import generateId from './utils/general/generateId.js'
7
+ import getRandomBytes from './utils/general/getRandomBytes.js'
8
+ import isJSON from './utils/general/isJSON.js'
9
+ import shuffle from './utils/general/shuffle.js'
10
+ import wait from './utils/general/wait.js'
11
+ import md5 from './utils/general/md5.js'
12
+ import getRandInteger from './utils/integer/getRandInteger.js'
13
+ import getRandString from './utils/string/getRandString.js'
14
+
15
+ const getRandomArrayItem = getRandArrayItem
16
+ const getRandomFloat = getRandFloat
17
+ const getRandomInteger = getRandInteger
18
+ const getRandomString = getRandString
19
+ const generateUuidV4 = generateBigId
20
+ const generateHexId = generateId
21
+
22
+ const sharedUtils = {
23
+ getRandArrayItem,
24
+ chunkArray,
25
+ getRandFloat,
26
+ chance,
27
+ generateBigId,
28
+ generateId,
29
+ getRandomBytes,
30
+ isJSON,
31
+ shuffle,
32
+ wait,
33
+ md5,
34
+ getRandInteger,
35
+ getRandString,
36
+ getRandomArrayItem,
37
+ getRandomFloat,
38
+ getRandomInteger,
39
+ getRandomString,
40
+ generateUuidV4,
41
+ generateHexId,
42
+ }
43
+
44
+ export {
45
+ getRandArrayItem,
46
+ chunkArray,
47
+ getRandFloat,
48
+ chance,
49
+ generateBigId,
50
+ generateId,
51
+ getRandomBytes,
52
+ isJSON,
53
+ shuffle,
54
+ wait,
55
+ md5,
56
+ getRandInteger,
57
+ getRandString,
58
+ getRandomArrayItem,
59
+ getRandomFloat,
60
+ getRandomInteger,
61
+ getRandomString,
62
+ generateUuidV4,
63
+ generateHexId,
64
+ }
65
+
66
+ export default sharedUtils
@@ -1,4 +1,12 @@
1
- export default (array, chunkSize) => {
1
+ export default function chunkArray(array, chunkSize) {
2
+ if (!Array.isArray(array)) {
3
+ throw new TypeError('array must be an array')
4
+ }
5
+
6
+ if (!Number.isInteger(chunkSize) || chunkSize <= 0) {
7
+ throw new TypeError('chunkSize must be a positive integer')
8
+ }
9
+
2
10
  const result = []
3
11
 
4
12
  for (let i = 0; i < array.length; i += chunkSize) {
@@ -1,3 +1,11 @@
1
- export default function (array) {
1
+ export default function getRandArrayItem(array) {
2
+ if (!Array.isArray(array)) {
3
+ throw new TypeError('array must be an array')
4
+ }
5
+
6
+ if (array.length === 0) {
7
+ return undefined
8
+ }
9
+
2
10
  return array[Math.floor(Math.random() * array.length)]
3
11
  }
@@ -1,8 +1,16 @@
1
- export default function (min, max, decimalPoint = 5) {
2
- let nums = [1, 2, 3, 4, 5, 6, 7, 8, 9]
3
- let numString = ''
4
- for (let i = 0; i < decimalPoint; i++) {
5
- numString += Math.floor(Math.random() * nums.length)
1
+ export default function getRandFloat(min, max, decimalPoint = 5) {
2
+ if (!Number.isFinite(min) || !Number.isFinite(max)) {
3
+ throw new TypeError('min and max must be finite numbers')
6
4
  }
7
- return parseFloat(`${this.getRandInteger(min, max)}.${numString})}`)
5
+
6
+ if (!Number.isInteger(decimalPoint) || decimalPoint < 0 || decimalPoint > 15) {
7
+ throw new RangeError('decimalPoint must be an integer from 0 to 15')
8
+ }
9
+
10
+ const lowerBound = Math.min(min, max)
11
+ const upperBound = Math.max(min, max)
12
+ const factor = 10 ** decimalPoint
13
+ const value = Math.random() * (upperBound - lowerBound) + lowerBound
14
+
15
+ return Math.round(value * factor) / factor
8
16
  }
@@ -1,7 +1,15 @@
1
- export default function (percent) {
2
- if (Math.ceil(Math.random() * 100) <= percent) {
1
+ export default function chance(percent) {
2
+ if (!Number.isFinite(percent)) {
3
+ throw new TypeError('percent must be a finite number')
4
+ }
5
+
6
+ if (percent <= 0) {
7
+ return false
8
+ }
9
+
10
+ if (percent >= 100) {
3
11
  return true
4
12
  }
5
13
 
6
- return false
14
+ return Math.random() * 100 < percent
7
15
  }
@@ -1,6 +1,11 @@
1
- export default function () {
2
- return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (e) {
3
- var t = (16 * Math.random()) | 0
4
- return ('x' === e ? t : (3 & t) | 8).toString(16)
5
- })
1
+ import getRandomBytes from './getRandomBytes.js'
2
+
3
+ export default function generateBigId() {
4
+ const bytes = getRandomBytes(16)
5
+
6
+ bytes[6] = (bytes[6] & 0x0f) | 0x40
7
+ bytes[8] = (bytes[8] & 0x3f) | 0x80
8
+
9
+ const hex = Array.from(bytes, (byte) => byte.toString(16).padStart(2, '0')).join('')
10
+ return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`
6
11
  }
@@ -1,6 +1,5 @@
1
- export default function () {
2
- return 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'.replace(/[xy]/g, function (e) {
3
- let t = (16 * Math.random()) | 0
4
- return ('x' === e ? t : (3 & t) | 8).toString(16)
5
- })
1
+ import getRandomBytes from './getRandomBytes.js'
2
+
3
+ export default function generateId() {
4
+ return Array.from(getRandomBytes(16), (byte) => byte.toString(16).padStart(2, '0')).join('')
6
5
  }
@@ -0,0 +1,16 @@
1
+ export default function getRandomBytes(length) {
2
+ if (!Number.isInteger(length) || length <= 0) {
3
+ throw new TypeError('length must be a positive integer')
4
+ }
5
+
6
+ if (globalThis.crypto && typeof globalThis.crypto.getRandomValues === 'function') {
7
+ return globalThis.crypto.getRandomValues(new Uint8Array(length))
8
+ }
9
+
10
+ const bytes = new Uint8Array(length)
11
+ for (let index = 0; index < bytes.length; index += 1) {
12
+ bytes[index] = Math.floor(Math.random() * 256)
13
+ }
14
+
15
+ return bytes
16
+ }
@@ -1,7 +1,12 @@
1
- export default function (json) {
1
+ export default function isJSON(json) {
2
+ if (typeof json !== 'string') {
3
+ return false
4
+ }
5
+
2
6
  try {
3
- if (JSON.parse(json)) return true
4
- } catch (e) {
7
+ JSON.parse(json)
8
+ return true
9
+ } catch {
5
10
  return false
6
11
  }
7
12
  }
@@ -1,5 +1,200 @@
1
- import crypto from 'crypto'
1
+ function rotateLeft(value, shift) {
2
+ return (value << shift) | (value >>> (32 - shift))
3
+ }
4
+
5
+ function addUnsigned(left, right) {
6
+ const leftHigh = left & 0x80000000
7
+ const rightHigh = right & 0x80000000
8
+ const leftMid = left & 0x40000000
9
+ const rightMid = right & 0x40000000
10
+ const result = (left & 0x3fffffff) + (right & 0x3fffffff)
11
+
12
+ if (leftMid & rightMid) {
13
+ return result ^ 0x80000000 ^ leftHigh ^ rightHigh
14
+ }
15
+
16
+ if (leftMid | rightMid) {
17
+ if (result & 0x40000000) {
18
+ return result ^ 0xc0000000 ^ leftHigh ^ rightHigh
19
+ }
20
+
21
+ return result ^ 0x40000000 ^ leftHigh ^ rightHigh
22
+ }
23
+
24
+ return result ^ leftHigh ^ rightHigh
25
+ }
26
+
27
+ function f(x, y, z) {
28
+ return (x & y) | (~x & z)
29
+ }
30
+
31
+ function g(x, y, z) {
32
+ return (x & z) | (y & ~z)
33
+ }
34
+
35
+ function h(x, y, z) {
36
+ return x ^ y ^ z
37
+ }
38
+
39
+ function i(x, y, z) {
40
+ return y ^ (x | ~z)
41
+ }
42
+
43
+ function ff(a, b, c, d, x, s, ac) {
44
+ return addUnsigned(rotateLeft(addUnsigned(addUnsigned(a, f(b, c, d)), addUnsigned(x, ac)), s), b)
45
+ }
46
+
47
+ function gg(a, b, c, d, x, s, ac) {
48
+ return addUnsigned(rotateLeft(addUnsigned(addUnsigned(a, g(b, c, d)), addUnsigned(x, ac)), s), b)
49
+ }
50
+
51
+ function hh(a, b, c, d, x, s, ac) {
52
+ return addUnsigned(rotateLeft(addUnsigned(addUnsigned(a, h(b, c, d)), addUnsigned(x, ac)), s), b)
53
+ }
54
+
55
+ function ii(a, b, c, d, x, s, ac) {
56
+ return addUnsigned(rotateLeft(addUnsigned(addUnsigned(a, i(b, c, d)), addUnsigned(x, ac)), s), b)
57
+ }
58
+
59
+ function toWordArray(value) {
60
+ const messageLength = value.length
61
+ const numberOfWordsTemp1 = messageLength + 8
62
+ const numberOfWordsTemp2 = (numberOfWordsTemp1 - (numberOfWordsTemp1 % 64)) / 64
63
+ const numberOfWords = (numberOfWordsTemp2 + 1) * 16
64
+ const wordArray = Array(numberOfWords - 1)
65
+ let byteIndex = 0
66
+ let wordIndex
67
+
68
+ while (byteIndex < messageLength) {
69
+ wordIndex = (byteIndex - (byteIndex % 4)) / 4
70
+ wordArray[wordIndex] = wordArray[wordIndex] || 0
71
+ wordArray[wordIndex] |= value.charCodeAt(byteIndex) << ((byteIndex % 4) * 8)
72
+ byteIndex += 1
73
+ }
74
+
75
+ wordIndex = (byteIndex - (byteIndex % 4)) / 4
76
+ wordArray[wordIndex] = wordArray[wordIndex] || 0
77
+ wordArray[wordIndex] |= 0x80 << ((byteIndex % 4) * 8)
78
+ wordArray[numberOfWords - 2] = messageLength << 3
79
+ wordArray[numberOfWords - 1] = messageLength >>> 29
80
+
81
+ return wordArray
82
+ }
83
+
84
+ function toHex(value) {
85
+ let word = ''
86
+
87
+ for (let index = 0; index <= 3; index += 1) {
88
+ const byte = (value >>> (index * 8)) & 255
89
+ word += `0${byte.toString(16)}`.slice(-2)
90
+ }
91
+
92
+ return word
93
+ }
94
+
95
+ function toUtf8(value) {
96
+ const bytes = new TextEncoder().encode(value)
97
+ let result = ''
98
+
99
+ for (let index = 0; index < bytes.length; index += 1) {
100
+ result += String.fromCharCode(bytes[index])
101
+ }
102
+
103
+ return result
104
+ }
105
+
106
+ export default function md5(data) {
107
+ let str
108
+ if ((typeof Buffer !== 'undefined' && Buffer.isBuffer(data)) || data instanceof Uint8Array) {
109
+ str = Array.from(data, (b) => String.fromCharCode(b)).join('')
110
+ } else {
111
+ str = toUtf8(String(data))
112
+ }
113
+ const x = toWordArray(str)
114
+ let a = 0x67452301
115
+ let b = 0xefcdab89
116
+ let c = 0x98badcfe
117
+ let d = 0x10325476
118
+
119
+ for (let index = 0; index < x.length; index += 16) {
120
+ const aOld = a
121
+ const bOld = b
122
+ const cOld = c
123
+ const dOld = d
124
+
125
+ a = ff(a, b, c, d, x[index + 0], 7, 0xd76aa478)
126
+ d = ff(d, a, b, c, x[index + 1], 12, 0xe8c7b756)
127
+ c = ff(c, d, a, b, x[index + 2], 17, 0x242070db)
128
+ b = ff(b, c, d, a, x[index + 3], 22, 0xc1bdceee)
129
+ a = ff(a, b, c, d, x[index + 4], 7, 0xf57c0faf)
130
+ d = ff(d, a, b, c, x[index + 5], 12, 0x4787c62a)
131
+ c = ff(c, d, a, b, x[index + 6], 17, 0xa8304613)
132
+ b = ff(b, c, d, a, x[index + 7], 22, 0xfd469501)
133
+ a = ff(a, b, c, d, x[index + 8], 7, 0x698098d8)
134
+ d = ff(d, a, b, c, x[index + 9], 12, 0x8b44f7af)
135
+ c = ff(c, d, a, b, x[index + 10], 17, 0xffff5bb1)
136
+ b = ff(b, c, d, a, x[index + 11], 22, 0x895cd7be)
137
+ a = ff(a, b, c, d, x[index + 12], 7, 0x6b901122)
138
+ d = ff(d, a, b, c, x[index + 13], 12, 0xfd987193)
139
+ c = ff(c, d, a, b, x[index + 14], 17, 0xa679438e)
140
+ b = ff(b, c, d, a, x[index + 15], 22, 0x49b40821)
141
+
142
+ a = gg(a, b, c, d, x[index + 1], 5, 0xf61e2562)
143
+ d = gg(d, a, b, c, x[index + 6], 9, 0xc040b340)
144
+ c = gg(c, d, a, b, x[index + 11], 14, 0x265e5a51)
145
+ b = gg(b, c, d, a, x[index + 0], 20, 0xe9b6c7aa)
146
+ a = gg(a, b, c, d, x[index + 5], 5, 0xd62f105d)
147
+ d = gg(d, a, b, c, x[index + 10], 9, 0x02441453)
148
+ c = gg(c, d, a, b, x[index + 15], 14, 0xd8a1e681)
149
+ b = gg(b, c, d, a, x[index + 4], 20, 0xe7d3fbc8)
150
+ a = gg(a, b, c, d, x[index + 9], 5, 0x21e1cde6)
151
+ d = gg(d, a, b, c, x[index + 14], 9, 0xc33707d6)
152
+ c = gg(c, d, a, b, x[index + 3], 14, 0xf4d50d87)
153
+ b = gg(b, c, d, a, x[index + 8], 20, 0x455a14ed)
154
+ a = gg(a, b, c, d, x[index + 13], 5, 0xa9e3e905)
155
+ d = gg(d, a, b, c, x[index + 2], 9, 0xfcefa3f8)
156
+ c = gg(c, d, a, b, x[index + 7], 14, 0x676f02d9)
157
+ b = gg(b, c, d, a, x[index + 12], 20, 0x8d2a4c8a)
158
+
159
+ a = hh(a, b, c, d, x[index + 5], 4, 0xfffa3942)
160
+ d = hh(d, a, b, c, x[index + 8], 11, 0x8771f681)
161
+ c = hh(c, d, a, b, x[index + 11], 16, 0x6d9d6122)
162
+ b = hh(b, c, d, a, x[index + 14], 23, 0xfde5380c)
163
+ a = hh(a, b, c, d, x[index + 1], 4, 0xa4beea44)
164
+ d = hh(d, a, b, c, x[index + 4], 11, 0x4bdecfa9)
165
+ c = hh(c, d, a, b, x[index + 7], 16, 0xf6bb4b60)
166
+ b = hh(b, c, d, a, x[index + 10], 23, 0xbebfbc70)
167
+ a = hh(a, b, c, d, x[index + 13], 4, 0x289b7ec6)
168
+ d = hh(d, a, b, c, x[index + 0], 11, 0xeaa127fa)
169
+ c = hh(c, d, a, b, x[index + 3], 16, 0xd4ef3085)
170
+ b = hh(b, c, d, a, x[index + 6], 23, 0x04881d05)
171
+ a = hh(a, b, c, d, x[index + 9], 4, 0xd9d4d039)
172
+ d = hh(d, a, b, c, x[index + 12], 11, 0xe6db99e5)
173
+ c = hh(c, d, a, b, x[index + 15], 16, 0x1fa27cf8)
174
+ b = hh(b, c, d, a, x[index + 2], 23, 0xc4ac5665)
175
+
176
+ a = ii(a, b, c, d, x[index + 0], 6, 0xf4292244)
177
+ d = ii(d, a, b, c, x[index + 7], 10, 0x432aff97)
178
+ c = ii(c, d, a, b, x[index + 14], 15, 0xab9423a7)
179
+ b = ii(b, c, d, a, x[index + 5], 21, 0xfc93a039)
180
+ a = ii(a, b, c, d, x[index + 12], 6, 0x655b59c3)
181
+ d = ii(d, a, b, c, x[index + 3], 10, 0x8f0ccc92)
182
+ c = ii(c, d, a, b, x[index + 10], 15, 0xffeff47d)
183
+ b = ii(b, c, d, a, x[index + 1], 21, 0x85845dd1)
184
+ a = ii(a, b, c, d, x[index + 8], 6, 0x6fa87e4f)
185
+ d = ii(d, a, b, c, x[index + 15], 10, 0xfe2ce6e0)
186
+ c = ii(c, d, a, b, x[index + 6], 15, 0xa3014314)
187
+ b = ii(b, c, d, a, x[index + 13], 21, 0x4e0811a1)
188
+ a = ii(a, b, c, d, x[index + 4], 6, 0xf7537e82)
189
+ d = ii(d, a, b, c, x[index + 11], 10, 0xbd3af235)
190
+ c = ii(c, d, a, b, x[index + 2], 15, 0x2ad7d2bb)
191
+ b = ii(b, c, d, a, x[index + 9], 21, 0xeb86d391)
192
+
193
+ a = addUnsigned(a, aOld)
194
+ b = addUnsigned(b, bOld)
195
+ c = addUnsigned(c, cOld)
196
+ d = addUnsigned(d, dOld)
197
+ }
2
198
 
3
- export default function (data) {
4
- return crypto.createHash('md5').update(data).digest('hex')
199
+ return `${toHex(a)}${toHex(b)}${toHex(c)}${toHex(d)}`.toLowerCase()
5
200
  }
@@ -1,7 +1,14 @@
1
- export default function (variable) {
2
- return Array(variable.length)
3
- .fill(null)
4
- .map((_, i) => [Math.random(), i])
5
- .sort(([a], [b]) => a - b)
6
- .map(([, i]) => variable[i])
1
+ export default function shuffle(variable) {
2
+ if (!Array.isArray(variable)) {
3
+ throw new TypeError('variable must be an array')
4
+ }
5
+
6
+ const result = [...variable]
7
+
8
+ for (let index = result.length - 1; index > 0; index -= 1) {
9
+ const randomIndex = Math.floor(Math.random() * (index + 1))
10
+ ;[result[index], result[randomIndex]] = [result[randomIndex], result[index]]
11
+ }
12
+
13
+ return result
7
14
  }
@@ -1,7 +1,9 @@
1
- export default function (miliseconds) {
1
+ export default function wait(milliseconds) {
2
+ if (!Number.isFinite(milliseconds) || milliseconds < 0) {
3
+ throw new TypeError('milliseconds must be a non-negative number')
4
+ }
5
+
2
6
  return new Promise((resolve) => {
3
- setTimeout(() => {
4
- resolve()
5
- }, miliseconds)
7
+ setTimeout(resolve, milliseconds)
6
8
  })
7
9
  }
@@ -1,3 +1,14 @@
1
- export default function (min, max) {
2
- return Math.floor(Math.random() * (Math.floor(max) - Math.ceil(min) + 1)) + Math.ceil(min)
1
+ export default function getRandInteger(min, max) {
2
+ if (!Number.isFinite(min) || !Number.isFinite(max)) {
3
+ throw new TypeError('min and max must be finite numbers')
4
+ }
5
+
6
+ const lowerBound = Math.ceil(Math.min(min, max))
7
+ const upperBound = Math.floor(Math.max(min, max))
8
+
9
+ if (lowerBound > upperBound) {
10
+ throw new RangeError('min and max do not contain an integer range')
11
+ }
12
+
13
+ return Math.floor(Math.random() * (upperBound - lowerBound + 1)) + lowerBound
3
14
  }
@@ -1,31 +1,38 @@
1
- import os from 'os'
1
+ import os from 'node:os'
2
2
 
3
- export default function (ms = 1000, free = false) {
4
- function getCPUInfo() {
5
- let stats = os.cpus().map((cpu) => {
6
- return {
7
- total: cpu.times.user + cpu.times.nice + cpu.times.sys + cpu.times.idle + cpu.times.irq,
8
- idle: cpu.times.idle,
9
- }
10
- })
3
+ function sampleCPUInfo() {
4
+ const stats = os.cpus().map((cpu) => {
5
+ return {
6
+ total: cpu.times.user + cpu.times.nice + cpu.times.sys + cpu.times.idle + cpu.times.irq,
7
+ idle: cpu.times.idle,
8
+ }
9
+ })
11
10
 
12
- return stats.reduce((a, b) => {
11
+ return stats.reduce(
12
+ (accumulator, current) => {
13
13
  return {
14
- total: a.total + b.total,
15
- idle: a.idle + b.idle,
14
+ total: accumulator.total + current.total,
15
+ idle: accumulator.idle + current.idle,
16
16
  }
17
- })
17
+ },
18
+ { total: 0, idle: 0 }
19
+ )
20
+ }
21
+
22
+ export default function getCPUUsage(ms = 1000, free = false) {
23
+ if (!Number.isFinite(ms) || ms < 0) {
24
+ throw new TypeError('ms must be a non-negative number')
18
25
  }
19
26
 
20
27
  return new Promise((resolve) => {
21
- const startStats = getCPUInfo()
28
+ const startStats = sampleCPUInfo()
29
+
22
30
  setTimeout(() => {
23
- const endStats = getCPUInfo()
24
- if (free) {
25
- resolve((endStats.idle - startStats.idle) / (endStats.total - startStats.total))
26
- } else {
27
- resolve(1 - (endStats.idle - startStats.idle) / (endStats.total - startStats.total))
28
- }
31
+ const endStats = sampleCPUInfo()
32
+ const totalDelta = endStats.total - startStats.total
33
+ const idleDelta = endStats.idle - startStats.idle
34
+ const idleRatio = totalDelta === 0 ? 0 : idleDelta / totalDelta
35
+ resolve(free ? idleRatio : 1 - idleRatio)
29
36
  }, ms)
30
37
  })
31
38
  }
@@ -1,20 +1,24 @@
1
- import os from 'os'
1
+ import os from 'node:os'
2
2
 
3
- export default function () {
4
- let networkInterfaces = os.networkInterfaces()
3
+ function isIPv4Interface(networkInterface) {
4
+ return (networkInterface.family === 'IPv4' || networkInterface.family === 4) && !networkInterface.internal
5
+ }
6
+
7
+ export default function getLocalAddress() {
8
+ const networkInterfaces = os.networkInterfaces()
9
+ const addresses = []
5
10
 
6
- let localAddresses = []
7
- for (let index in networkInterfaces) {
8
- let interIPv4 = networkInterfaces[index]
9
- .filter((inter) => {
10
- return inter.family == 'IPv4' && inter.address != '127.0.0.1'
11
- })
12
- .map((inter) => {
13
- return inter.address
14
- })
11
+ for (const interfaces of Object.values(networkInterfaces)) {
12
+ if (!Array.isArray(interfaces)) {
13
+ continue
14
+ }
15
15
 
16
- localAddresses = localAddresses.concat(interIPv4)
16
+ for (const networkInterface of interfaces) {
17
+ if (isIPv4Interface(networkInterface)) {
18
+ addresses.push(networkInterface.address)
19
+ }
20
+ }
17
21
  }
18
22
 
19
- return localAddresses[0]
23
+ return addresses[0]
20
24
  }
@@ -1,20 +1,24 @@
1
- import os from 'os'
1
+ import os from 'node:os'
2
2
 
3
- export default function () {
4
- let networkInterfaces = os.networkInterfaces()
3
+ function isIPv4Interface(networkInterface) {
4
+ return (networkInterface.family === 'IPv4' || networkInterface.family === 4) && !networkInterface.internal
5
+ }
6
+
7
+ export default function getLocalAddresses() {
8
+ const networkInterfaces = os.networkInterfaces()
9
+ const addresses = []
5
10
 
6
- let localAddresses = []
7
- for (let index in networkInterfaces) {
8
- let interIPv4 = networkInterfaces[index]
9
- .filter((inter) => {
10
- return inter.family == 'IPv4' && inter.address != '127.0.0.1'
11
- })
12
- .map((inter) => {
13
- return inter.address
14
- })
11
+ for (const interfaces of Object.values(networkInterfaces)) {
12
+ if (!Array.isArray(interfaces)) {
13
+ continue
14
+ }
15
15
 
16
- localAddresses = localAddresses.concat(interIPv4)
16
+ for (const networkInterface of interfaces) {
17
+ if (isIPv4Interface(networkInterface)) {
18
+ addresses.push(networkInterface.address)
19
+ }
20
+ }
17
21
  }
18
22
 
19
- return localAddresses
23
+ return addresses
20
24
  }
@@ -1,9 +1,16 @@
1
- export default function (length = 16, charSet) {
2
- var result = []
3
- charSet = charSet || 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
1
+ export default function getRandString(length = 16, charSet) {
2
+ if (!Number.isInteger(length) || length < 0) {
3
+ throw new TypeError('length must be a non-negative integer')
4
+ }
5
+
6
+ const normalizedCharSet = charSet === undefined ? 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789' : charSet
7
+ if (typeof normalizedCharSet !== 'string' || normalizedCharSet.length === 0) {
8
+ throw new TypeError('charSet must be a non-empty string')
9
+ }
4
10
 
5
- while (length--) {
6
- result.push(charSet[Math.floor(Math.random() * charSet.length)])
11
+ const result = []
12
+ for (let index = 0; index < length; index += 1) {
13
+ result.push(normalizedCharSet[Math.floor(Math.random() * normalizedCharSet.length)])
7
14
  }
8
15
 
9
16
  return result.join('')
package/.eslintrc DELETED
@@ -1,21 +0,0 @@
1
- {
2
- "extends": ["airbnb", "eslint-config-airbnb-base", "prettier"],
3
- "rules": {
4
- "indent": ["error", 4],
5
- "semi": "off",
6
- "prettier/prettier": ["error"],
7
- "no-unused-vars": "warn",
8
- "max-len": ["error", { "code": 150 }],
9
- "no-console": "off",
10
- "import/extensions": "off"
11
- },
12
- "parserOptions": {
13
- "ecmaVersion": 2022,
14
- "sourceType": "module"
15
- },
16
- "env": {
17
- "es6": true,
18
- "node": true
19
- },
20
- "plugins": ["import", "prettier", "node"]
21
- }
package/.prettierrc DELETED
@@ -1,11 +0,0 @@
1
- {
2
- "singleQuote": true,
3
- "semi": false,
4
- "tabWidth": 4,
5
- "printWidth": 150,
6
- "arrowParens": "always",
7
- "bracketSpacing": true,
8
- "arrayBracketSpacing": true,
9
- "jsxBracketSameLine": false,
10
- "trailingComma": "es5"
11
- }
package/tests/index.js DELETED
@@ -1,25 +0,0 @@
1
- import utils from '../src/index.js'
2
-
3
- // ARRAY
4
- console.log(utils.getRandArrayItem([1, 2, 3, 4, 5, 6, 7, 8, 9]))
5
-
6
- // FLOAT
7
- console.log(utils.getRandFloat(0, 1, 3))
8
-
9
- // GENERAL
10
- console.log(utils.chance(20))
11
- console.log(utils.generateBigId())
12
- console.log(utils.generateId())
13
- console.log(utils.isJSON('{}'))
14
- console.log(utils.shuffle([1, 2, 3, 4, 5, 6, 7, 8]))
15
- console.log(utils.wait(1000))
16
-
17
- // INTEGER
18
- console.log(utils.getRandInteger(1, 2000))
19
-
20
- // OS
21
- console.log(utils.getLocalAddress())
22
- console.log(utils.getLocalAddresses())
23
-
24
- // STRING
25
- console.log(utils.getRandString(2))