@inglorious/utils 3.3.0 → 3.5.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.
- package/package.json +3 -2
- package/src/math/rng.js +31 -6
- package/src/math/rng.test.js +17 -1
- package/src/math/vector.js +5 -5
- package/src/v.js +24 -0
- package/src/v.test.js +36 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inglorious/utils",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.5.0",
|
|
4
4
|
"description": "A set of general-purpose utility functions designed with functional programming principles in mind.",
|
|
5
5
|
"author": "IceOnFire <antony.mistretta@gmail.com> (https://ingloriouscoderz.it)",
|
|
6
6
|
"license": "MIT",
|
|
@@ -32,7 +32,8 @@
|
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"prettier": "^3.6.2",
|
|
34
34
|
"vite": "^7.1.3",
|
|
35
|
-
"vitest": "^1.6.1"
|
|
35
|
+
"vitest": "^1.6.1",
|
|
36
|
+
"@inglorious/eslint-config": "1.0.0"
|
|
36
37
|
},
|
|
37
38
|
"engines": {
|
|
38
39
|
"node": ">= 22"
|
package/src/math/rng.js
CHANGED
|
@@ -1,22 +1,47 @@
|
|
|
1
1
|
/* eslint-disable no-magic-numbers */
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Chooses a random value from the given arguments.
|
|
5
|
+
* @param {...*} values - The values to choose from.
|
|
6
|
+
* @returns {*} A randomly selected value.
|
|
7
|
+
*/
|
|
8
|
+
export function choose(...values) {
|
|
9
|
+
if (!values.length) {
|
|
10
|
+
return undefined
|
|
11
|
+
}
|
|
12
|
+
const index = random(values.length - 1)
|
|
13
|
+
return values[index]
|
|
14
|
+
}
|
|
15
|
+
|
|
3
16
|
/**
|
|
4
17
|
* Generates a random number.
|
|
5
18
|
* - If no arguments are provided, returns a random float between 0 (inclusive) and 1 (exclusive).
|
|
6
|
-
* - If one argument is provided, returns a random integer between 0 and
|
|
7
|
-
* - If two
|
|
8
|
-
*
|
|
9
|
-
*
|
|
19
|
+
* - If one argument (`to`) is provided, returns a random integer between 0 and `to` (inclusive).
|
|
20
|
+
* - If two arguments (`from`, `to`) are provided:
|
|
21
|
+
* - If they are integers, returns a random integer between `from` and `to` (inclusive).
|
|
22
|
+
* - If they are floats, returns a random float between `from` (inclusive) and `to` (exclusive).
|
|
23
|
+
* - If three arguments (`from`, `to`, `step`) are provided, returns a random integer within the specified range and step.
|
|
24
|
+
* @param {number} [to] - The upper bound.
|
|
25
|
+
* @param {number} [from] - The lower bound.
|
|
10
26
|
* @param {number} [step=1] - The step size if two or more arguments are provided.
|
|
11
27
|
* @returns {number} A random number based on the provided arguments.
|
|
12
28
|
*/
|
|
13
29
|
export function random(...args) {
|
|
14
|
-
let step, from, to
|
|
15
|
-
|
|
16
30
|
if (!args.length) {
|
|
17
31
|
return Math.random()
|
|
18
32
|
}
|
|
19
33
|
|
|
34
|
+
if (
|
|
35
|
+
args.length > 1 &&
|
|
36
|
+
!Number.isInteger(args[0]) &&
|
|
37
|
+
!Number.isInteger(args[1])
|
|
38
|
+
) {
|
|
39
|
+
const [from, to] = args
|
|
40
|
+
return Math.random() * (to - from) + from
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
let step, from, to
|
|
44
|
+
|
|
20
45
|
if (args.length === 1) {
|
|
21
46
|
step = 1
|
|
22
47
|
from = 0
|
package/src/math/rng.test.js
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import { expect, test } from "vitest"
|
|
2
2
|
|
|
3
|
-
import { random, randomBinomial } from "./rng.js"
|
|
3
|
+
import { choose, random, randomBinomial } from "./rng.js"
|
|
4
|
+
|
|
5
|
+
test("it should choose a random value from the given arguments", () => {
|
|
6
|
+
const values = ["a", "b", "c"]
|
|
7
|
+
const chosenValue = choose(...values)
|
|
8
|
+
|
|
9
|
+
expect(values).toContain(chosenValue)
|
|
10
|
+
})
|
|
4
11
|
|
|
5
12
|
test("it should create a random number in the range [0, 1)", () => {
|
|
6
13
|
const randomNumber = random()
|
|
@@ -31,6 +38,15 @@ test("it should create a random even number in the range [2, 6]", () => {
|
|
|
31
38
|
expect(randomNumber % 2).toBe(0)
|
|
32
39
|
})
|
|
33
40
|
|
|
41
|
+
test("it should create a random float in the range [1.5, 6.5)", () => {
|
|
42
|
+
const from = 1.5
|
|
43
|
+
const to = 6.5
|
|
44
|
+
const randomNumber = random(from, to)
|
|
45
|
+
|
|
46
|
+
expect(randomNumber).toBeGreaterThanOrEqual(from)
|
|
47
|
+
expect(randomNumber).toBeLessThan(to)
|
|
48
|
+
})
|
|
49
|
+
|
|
34
50
|
test("it should create a random number in the range (-1, 1)", () => {
|
|
35
51
|
const randomNumber = randomBinomial()
|
|
36
52
|
|
package/src/math/vector.js
CHANGED
|
@@ -93,7 +93,7 @@ export function conjugate(vector) {
|
|
|
93
93
|
* @returns {Vector3} The created 3D vector.
|
|
94
94
|
*/
|
|
95
95
|
export function createVector(magnitude, angle) {
|
|
96
|
-
return
|
|
96
|
+
return scale(fromAngle(angle), magnitude)
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
/**
|
|
@@ -221,9 +221,9 @@ export const remainder = mod
|
|
|
221
221
|
export function rotate(vector, angle) {
|
|
222
222
|
const is2D = vector.length === TWO_COORDINATES
|
|
223
223
|
|
|
224
|
-
|
|
224
|
+
const vector3 = is2D ? from2D(vector) : vector
|
|
225
225
|
|
|
226
|
-
|
|
226
|
+
const result = rotateWithQuaternion(vector3, angle)
|
|
227
227
|
|
|
228
228
|
return is2D ? to2D(result) : result
|
|
229
229
|
}
|
|
@@ -254,7 +254,7 @@ export const setLength = setMagnitude
|
|
|
254
254
|
*/
|
|
255
255
|
export function setMagnitude(vector, length) {
|
|
256
256
|
const normalized = normalize(vector)
|
|
257
|
-
return
|
|
257
|
+
return scale(normalized, length)
|
|
258
258
|
}
|
|
259
259
|
|
|
260
260
|
/**
|
|
@@ -389,7 +389,7 @@ function rotateWithQuaternion(vector, angle) {
|
|
|
389
389
|
const [w, ...r] = quaternion(angle)
|
|
390
390
|
const result = sum(
|
|
391
391
|
vector,
|
|
392
|
-
cross(
|
|
392
|
+
cross(scale(r, 2), sum(cross(r, vector), scale(vector, w))), // eslint-disable-line no-magic-numbers
|
|
393
393
|
)
|
|
394
394
|
|
|
395
395
|
return conjugate(result) // HACK: not really sure why I should invert the result, it just works this way
|
package/src/v.js
CHANGED
|
@@ -1,3 +1,27 @@
|
|
|
1
|
+
import { isArray } from "./data-structures/array"
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Ensures that a given value is a vector.
|
|
5
|
+
*
|
|
6
|
+
* If the value is an array of finite numbers but not already a vector (i.e., it lacks the `__isVector__` property),
|
|
7
|
+
* this function converts it into a vector by calling `v()`. If the value is already a vector or not a numeric array,
|
|
8
|
+
* it is returned unchanged. This is particularly useful for ensuring that the results of standard array operations
|
|
9
|
+
* (like `.map()` or `.filter()`) which return a new array are correctly re-tagged as vectors.
|
|
10
|
+
* @param {*} value The value to check and potentially convert.
|
|
11
|
+
* @returns {Vector|*} The value as a vector, or the original value if no conversion was needed.
|
|
12
|
+
*/
|
|
13
|
+
export function ensureV(value) {
|
|
14
|
+
if (
|
|
15
|
+
isArray(value) &&
|
|
16
|
+
!value.__isVector__ &&
|
|
17
|
+
value.every((coord) => isFinite(coord))
|
|
18
|
+
) {
|
|
19
|
+
return v(...value)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return value
|
|
23
|
+
}
|
|
24
|
+
|
|
1
25
|
/**
|
|
2
26
|
* A utility function to create a vector from a list of coordinates.
|
|
3
27
|
* This is a shorthand for `[x, y, z, ...]`.
|
package/src/v.test.js
CHANGED
|
@@ -1,6 +1,41 @@
|
|
|
1
1
|
import { expect, test } from "vitest"
|
|
2
2
|
|
|
3
|
-
import { v } from "./v"
|
|
3
|
+
import { ensureV, v } from "./v"
|
|
4
|
+
|
|
5
|
+
test("ensureV() should convert a numeric array into a vector", () => {
|
|
6
|
+
const array = [1, 2, 3]
|
|
7
|
+
const result = ensureV(array)
|
|
8
|
+
expect(result).toStrictEqual([1, 2, 3])
|
|
9
|
+
expect(result.__isVector__).toBe(true)
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
test("ensureV() should return an existing vector unchanged", () => {
|
|
13
|
+
const vector = v(4, 5, 6)
|
|
14
|
+
const result = ensureV(vector)
|
|
15
|
+
expect(result).toBe(vector)
|
|
16
|
+
expect(result.__isVector__).toBe(true)
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
test("ensureV() should not convert an array with non-finite numbers", () => {
|
|
20
|
+
const array = [1, Infinity, 3]
|
|
21
|
+
const result = ensureV(array)
|
|
22
|
+
expect(result).toBe(array)
|
|
23
|
+
expect(result.__isVector__).toBeUndefined()
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
test("ensureV() should not convert an array with non-numeric values", () => {
|
|
27
|
+
const array = [1, "a", 3]
|
|
28
|
+
const result = ensureV(array)
|
|
29
|
+
expect(result).toBe(array)
|
|
30
|
+
expect(result.__isVector__).toBeUndefined()
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
test("ensureV() should return non-array values unchanged", () => {
|
|
34
|
+
expect(ensureV(123)).toBe(123)
|
|
35
|
+
expect(ensureV("hello")).toBe("hello")
|
|
36
|
+
const obj = { a: 1 }
|
|
37
|
+
expect(ensureV(obj)).toBe(obj)
|
|
38
|
+
})
|
|
4
39
|
|
|
5
40
|
test("a vector created with the v() function is just a number array", () => {
|
|
6
41
|
const vector = v(1, 2, 3)
|