@inglorious/utils 3.2.0 → 3.4.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 +13 -0
- package/src/math/rng.test.js +8 -1
- package/src/math/vector.js +8 -13
- package/src/math/vector.test.js +1 -2
- 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.4.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,5 +1,18 @@
|
|
|
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).
|
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()
|
package/src/math/vector.js
CHANGED
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
* @typedef {import('./types').Vector3} Vector3
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { isArray } from "../data-structures/array.js"
|
|
8
7
|
import { v } from "../v.js"
|
|
9
8
|
import {
|
|
10
9
|
abs as nAbs,
|
|
@@ -94,7 +93,7 @@ export function conjugate(vector) {
|
|
|
94
93
|
* @returns {Vector3} The created 3D vector.
|
|
95
94
|
*/
|
|
96
95
|
export function createVector(magnitude, angle) {
|
|
97
|
-
return
|
|
96
|
+
return scale(fromAngle(angle), magnitude)
|
|
98
97
|
}
|
|
99
98
|
|
|
100
99
|
/**
|
|
@@ -128,17 +127,13 @@ export function fromAngle(angle) {
|
|
|
128
127
|
|
|
129
128
|
/**
|
|
130
129
|
* Checks if a value is a vector.
|
|
131
|
-
*
|
|
132
|
-
*
|
|
130
|
+
* This is determined by checking for the `__isVector__` property, which is
|
|
131
|
+
* added by the `v()` factory function for efficient type checking.
|
|
133
132
|
* @param {*} value - The value to check.
|
|
134
133
|
* @returns {boolean} True if the value is a vector, false otherwise.
|
|
135
134
|
*/
|
|
136
135
|
export function isVector(value) {
|
|
137
|
-
return
|
|
138
|
-
value?.__isVector__ ||
|
|
139
|
-
(isArray(value) &&
|
|
140
|
-
value.every((coordinate) => typeof coordinate === "number"))
|
|
141
|
-
)
|
|
136
|
+
return !!value?.__isVector__
|
|
142
137
|
}
|
|
143
138
|
|
|
144
139
|
/**
|
|
@@ -226,9 +221,9 @@ export const remainder = mod
|
|
|
226
221
|
export function rotate(vector, angle) {
|
|
227
222
|
const is2D = vector.length === TWO_COORDINATES
|
|
228
223
|
|
|
229
|
-
|
|
224
|
+
const vector3 = is2D ? from2D(vector) : vector
|
|
230
225
|
|
|
231
|
-
|
|
226
|
+
const result = rotateWithQuaternion(vector3, angle)
|
|
232
227
|
|
|
233
228
|
return is2D ? to2D(result) : result
|
|
234
229
|
}
|
|
@@ -259,7 +254,7 @@ export const setLength = setMagnitude
|
|
|
259
254
|
*/
|
|
260
255
|
export function setMagnitude(vector, length) {
|
|
261
256
|
const normalized = normalize(vector)
|
|
262
|
-
return
|
|
257
|
+
return scale(normalized, length)
|
|
263
258
|
}
|
|
264
259
|
|
|
265
260
|
/**
|
|
@@ -394,7 +389,7 @@ function rotateWithQuaternion(vector, angle) {
|
|
|
394
389
|
const [w, ...r] = quaternion(angle)
|
|
395
390
|
const result = sum(
|
|
396
391
|
vector,
|
|
397
|
-
cross(
|
|
392
|
+
cross(scale(r, 2), sum(cross(r, vector), scale(vector, w))), // eslint-disable-line no-magic-numbers
|
|
398
393
|
)
|
|
399
394
|
|
|
400
395
|
return conjugate(result) // HACK: not really sure why I should invert the result, it just works this way
|
package/src/math/vector.test.js
CHANGED
|
@@ -126,8 +126,7 @@ test("it should compute the magnitude of a vector (aka length)", () => {
|
|
|
126
126
|
})
|
|
127
127
|
|
|
128
128
|
test("it should check if a value is a vector", () => {
|
|
129
|
-
expect(isVector([1, 2, 3])).toBe(
|
|
130
|
-
expect(isVector([])).toBe(true)
|
|
129
|
+
expect(isVector([1, 2, 3])).toBe(false)
|
|
131
130
|
expect(isVector(v(1, 2, 3))).toBe(true)
|
|
132
131
|
})
|
|
133
132
|
|
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)
|