@inglorious/utils 3.7.3 → 4.0.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/README.md +67 -3
- package/package.json +89 -9
- package/src/algorithms/decision-tree.js +3 -3
- package/src/algorithms/path-finding.js +6 -6
- package/src/data-structures/board.js +97 -15
- package/src/data-structures/index.js +2 -2
- package/src/data-structures/objects.js +352 -34
- package/src/data-structures/string.js +13 -0
- package/src/data-structures/tree.js +1 -1
- package/src/functions/functions.js +168 -0
- package/src/functions/index.js +1 -4
- package/src/math/circle.js +5 -7
- package/src/math/index.js +0 -4
- package/src/math/line.js +3 -3
- package/src/math/point.js +10 -9
- package/src/math/quaternions.js +20 -4
- package/src/math/rectangle.js +4 -4
- package/src/math/segment.js +11 -5
- package/src/math/vectors.js +471 -65
- package/src/physics/acceleration.js +2 -3
- package/src/physics/friction.js +2 -2
- package/src/physics/gravity.js +2 -2
- package/src/physics/jump.js +0 -4
- package/src/physics/velocity.js +2 -3
- package/src/v.js +1 -1
- package/types/algorithms/decision-tree.d.ts +27 -0
- package/types/algorithms/index.d.ts +2 -0
- package/types/algorithms/path-finding.d.ts +69 -0
- package/types/data-structures/array.d.ts +56 -0
- package/types/data-structures/board.d.ts +121 -0
- package/types/data-structures/boolean.d.ts +4 -0
- package/types/data-structures/heap.d.ts +69 -0
- package/types/data-structures/index.d.ts +8 -0
- package/types/data-structures/objects.d.ts +237 -0
- package/types/data-structures/set.d.ts +4 -0
- package/types/data-structures/string.d.ts +7 -0
- package/types/data-structures/tree.d.ts +21 -0
- package/types/functions/functions.d.ts +57 -0
- package/types/functions/index.d.ts +1 -0
- package/types/index.d.ts +6 -4
- package/types/math/circle.d.ts +22 -0
- package/types/math/hitmask.d.ts +20 -0
- package/types/math/index.d.ts +14 -0
- package/types/math/line.d.ts +11 -0
- package/types/math/linear-interpolation.d.ts +2 -0
- package/types/math/numbers.d.ts +26 -0
- package/types/math/point.d.ts +25 -0
- package/types/math/quaternions.d.ts +10 -0
- package/types/math/rectangle.d.ts +36 -0
- package/types/math/rng.d.ts +14 -0
- package/types/math/segment.d.ts +23 -0
- package/types/math/statistics.d.ts +11 -0
- package/types/math/triangle.d.ts +5 -0
- package/types/math/trigonometry.d.ts +26 -0
- package/types/math/vectors.d.ts +190 -0
- package/types/physics/acceleration.d.ts +24 -0
- package/types/physics/friction.d.ts +11 -0
- package/types/physics/gravity.d.ts +20 -0
- package/types/physics/index.d.ts +5 -0
- package/types/physics/jump.d.ts +10 -0
- package/types/physics/velocity.d.ts +20 -0
- package/types/v.d.ts +7 -3
- package/src/data-structures/object.js +0 -320
- package/src/functions/function.js +0 -9
- package/src/math/quaternion.js +0 -22
- package/src/math/vector.js +0 -426
- package/types/algorithms.d.ts +0 -26
- package/types/data-structures.d.ts +0 -53
- package/types/math.d.ts +0 -90
|
@@ -1,320 +0,0 @@
|
|
|
1
|
-
import { v } from "../v.js"
|
|
2
|
-
import { isArray } from "./array.js"
|
|
3
|
-
|
|
4
|
-
const INITIAL_LEVEL = 0
|
|
5
|
-
const LAST_KEY_OFFSET = 1
|
|
6
|
-
const NEXT_KEY_OFFSET = 1
|
|
7
|
-
const NEXT_LEVEL = 2
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Creates a deep clone of a given value using the structured clone algorithm.
|
|
11
|
-
* This is a modern and efficient way to deep-clone objects.
|
|
12
|
-
*
|
|
13
|
-
* Note: `structuredClone` has some limitations. It cannot clone functions,
|
|
14
|
-
* DOM nodes, property descriptors, getters, setters, or certain other
|
|
15
|
-
* non-serializable objects. It will throw a `DataCloneError` in such cases.
|
|
16
|
-
*
|
|
17
|
-
* For more details, see:
|
|
18
|
-
* https://developer.mozilla.org/en-US/docs/Web/API/structuredClone
|
|
19
|
-
*
|
|
20
|
-
* This is similar to Lodash's `_.cloneDeep`.
|
|
21
|
-
*
|
|
22
|
-
* @template T
|
|
23
|
-
* @param {T} obj - The value to clone.
|
|
24
|
-
* @returns {T} A deep clone of the input value.
|
|
25
|
-
*/
|
|
26
|
-
export function clone(obj) {
|
|
27
|
-
return deserialize(serialize(obj))
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Deserializes an object, converting plain object representations back into
|
|
32
|
-
* their original types, such as vector-like objects. This is the inverse
|
|
33
|
-
* operation of `serialize`.
|
|
34
|
-
*
|
|
35
|
-
* - Recursively deserializes nested objects.
|
|
36
|
-
* - Converts objects with a `_type: "vector"` property and `coords` array
|
|
37
|
-
* back into a vector-like object using the `v` factory function.
|
|
38
|
-
* - Copies all other property values as-is.
|
|
39
|
-
*
|
|
40
|
-
* @param {string} str - The JSON string to deserialize.
|
|
41
|
-
* @returns {Object} The deserialized object.
|
|
42
|
-
*/
|
|
43
|
-
export function deserialize(str) {
|
|
44
|
-
const data = JSON.parse(str)
|
|
45
|
-
|
|
46
|
-
return revive(data)
|
|
47
|
-
|
|
48
|
-
function revive(value) {
|
|
49
|
-
if (isArray(value)) {
|
|
50
|
-
return value.map(revive)
|
|
51
|
-
}
|
|
52
|
-
if (isObject(value)) {
|
|
53
|
-
if (value._type === "vector" && value.coords) {
|
|
54
|
-
return v(...value.coords)
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const deserialized = {}
|
|
58
|
-
for (const key in value) {
|
|
59
|
-
if (Object.prototype.hasOwnProperty.call(value, key)) {
|
|
60
|
-
deserialized[key] = revive(value[key])
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
return deserialized
|
|
64
|
-
}
|
|
65
|
-
return value
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Filters the properties of an object based on a callback function.
|
|
71
|
-
*
|
|
72
|
-
* @param {Object} obj - The object to filter.
|
|
73
|
-
* @param {Function} callback - A function that determines whether a property should be included.
|
|
74
|
-
* Receives (key, value, obj) as arguments.
|
|
75
|
-
* @returns {Object} A new object with the filtered properties.
|
|
76
|
-
*/
|
|
77
|
-
export function filter(obj, callback) {
|
|
78
|
-
return Object.fromEntries(
|
|
79
|
-
Object.entries(obj).filter(([key, value], obj) =>
|
|
80
|
-
callback(key, value, obj),
|
|
81
|
-
),
|
|
82
|
-
)
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Finds the first property in an object that satisfies the callback function.
|
|
87
|
-
*
|
|
88
|
-
* @param {Object} obj - The object to search.
|
|
89
|
-
* @param {Function} callback - A function that determines whether a property matches.
|
|
90
|
-
* Receives (key, value, obj) as arguments.
|
|
91
|
-
* @returns {Object} An object containing the first matching property, or an empty object if none match.
|
|
92
|
-
*/
|
|
93
|
-
export function find(obj, callback) {
|
|
94
|
-
return Object.fromEntries([
|
|
95
|
-
Object.entries(obj).find(([key, value], obj) => callback(key, value, obj)),
|
|
96
|
-
])
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* Gets the value at a specified path of an object. If the resolved value is
|
|
101
|
-
* `undefined`, the `defaultValue` is returned in its place. This function
|
|
102
|
-
* supports dot-notation for nested properties and numbers for array indices.
|
|
103
|
-
*
|
|
104
|
-
* This is similar to Lodash's `_.get`.
|
|
105
|
-
*
|
|
106
|
-
* @example
|
|
107
|
-
* const object = { 'a': [{ 'b': { 'c': 3 } }] };
|
|
108
|
-
* get(object, 'a.0.b.c');
|
|
109
|
-
* // => 3
|
|
110
|
-
*
|
|
111
|
-
* get(object, 'a.0.d', 'default');
|
|
112
|
-
* // => 'default'
|
|
113
|
-
*
|
|
114
|
-
* @param {Object} obj - The object to query.
|
|
115
|
-
* @param {string} path - The path of the property to retrieve.
|
|
116
|
-
* @param {*} [defaultValue=undefined] - The value returned for `undefined` resolved values.
|
|
117
|
-
* @returns {*} Returns the resolved value, else the `defaultValue`.
|
|
118
|
-
*/
|
|
119
|
-
export function get(obj, path, defaultValue = undefined) {
|
|
120
|
-
if (!path) return defaultValue
|
|
121
|
-
|
|
122
|
-
const keys = path.split(".")
|
|
123
|
-
let result = obj
|
|
124
|
-
|
|
125
|
-
for (const key of keys) {
|
|
126
|
-
if (result == null || typeof result !== "object") {
|
|
127
|
-
return defaultValue
|
|
128
|
-
}
|
|
129
|
-
result = result[key]
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
return result !== undefined ? result : defaultValue
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
/**
|
|
136
|
-
* Checks if a value is a plain object.
|
|
137
|
-
*
|
|
138
|
-
* @param {*} value - The value to check.
|
|
139
|
-
* @returns {boolean} True if the value is a plain object, false otherwise.
|
|
140
|
-
*/
|
|
141
|
-
export function isObject(value) {
|
|
142
|
-
return value != null && value.constructor === Object
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* Maps the properties of an object using a callback function.
|
|
147
|
-
*
|
|
148
|
-
* @param {Object} obj - The object to map.
|
|
149
|
-
* @param {Function} callback - A function that transforms each property.
|
|
150
|
-
* Receives (key, value, obj) as arguments.
|
|
151
|
-
* @returns {Object} A new object with the mapped properties.
|
|
152
|
-
*/
|
|
153
|
-
export function map(obj, callback) {
|
|
154
|
-
return Object.entries(obj).reduce((acc, [key, value]) => {
|
|
155
|
-
acc[key] = callback(key, value, obj)
|
|
156
|
-
return acc
|
|
157
|
-
}, {})
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* A utility function inspired by Immer's `produce` API. It provides a convenient
|
|
162
|
-
* way to work with immutable data structures by allowing "mutations" on a
|
|
163
|
-
* temporary draft.
|
|
164
|
-
*
|
|
165
|
-
* **Important:** Unlike Immer, which uses structural sharing via proxies for
|
|
166
|
-
* high performance, this implementation performs a full deep clone of the base
|
|
167
|
-
* state on every call using `deserialize(serialize())`. This can be
|
|
168
|
-
* inefficient for large or complex states. It is intended for simple use cases
|
|
169
|
-
* where the convenience of the API outweighs the performance cost.
|
|
170
|
-
*
|
|
171
|
-
* The recipe function receives a draft copy of the state. It can either
|
|
172
|
-
* mutate the draft and return nothing (`undefined`), or it can return a
|
|
173
|
-
* completely new value, which will become the next state.
|
|
174
|
-
*
|
|
175
|
-
* Can be called in two ways:
|
|
176
|
-
* - **Standard:** `produce(baseState, recipe, ...args)`
|
|
177
|
-
* - **Curried:** `produce(recipe)` returns a new function `(baseState, ...args) => newState`
|
|
178
|
-
*
|
|
179
|
-
* @template T
|
|
180
|
-
* @param {T|function(T, ...*): (T|void)} baseState The initial state, or a recipe for currying.
|
|
181
|
-
* @param {function(T, ...*): (T|void)} [recipe] The recipe function.
|
|
182
|
-
* @param {...*} args Additional arguments to pass to the recipe.
|
|
183
|
-
* @returns {T | function(T, ...*): T} A new state, or a producer function if curried.
|
|
184
|
-
*/
|
|
185
|
-
export function produce(baseState, recipe, ...args) {
|
|
186
|
-
if (typeof baseState === "function" && recipe === undefined) {
|
|
187
|
-
const recipeFn = baseState
|
|
188
|
-
return (state, ...recipeArgs) => produce(state, recipeFn, ...recipeArgs)
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
const draft = clone(baseState)
|
|
192
|
-
const result = recipe(draft, ...args)
|
|
193
|
-
return result === undefined ? draft : result
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
/**
|
|
197
|
-
* Serializes an object, converting special types like vectors into a plain
|
|
198
|
-
* object representation. This is useful for processes like saving state to a
|
|
199
|
-
* file or sending it over a network.
|
|
200
|
-
*
|
|
201
|
-
* - Recursively serializes nested objects.
|
|
202
|
-
* - Converts objects with a `__isVector__` property into a serializable
|
|
203
|
-
* format: `{ _type: "vector", coords: [...] }`.
|
|
204
|
-
* - Copies all other property values as-is.
|
|
205
|
-
*
|
|
206
|
-
* @param {Object} obj - The object to serialize.
|
|
207
|
-
* @returns {string} The serialized JSON string.
|
|
208
|
-
*/
|
|
209
|
-
export function serialize(obj) {
|
|
210
|
-
function replacer(key, value) {
|
|
211
|
-
// Handle top-level vector
|
|
212
|
-
if (value?.__isVector__) {
|
|
213
|
-
return {
|
|
214
|
-
_type: "vector",
|
|
215
|
-
coords: Array.from(value),
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
if (isObject(value)) {
|
|
220
|
-
const serialized = {}
|
|
221
|
-
|
|
222
|
-
for (const k in value) {
|
|
223
|
-
if (Object.prototype.hasOwnProperty.call(value, k)) {
|
|
224
|
-
serialized[k] = replacer(undefined, value[k])
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
return serialized
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
return value
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
return JSON.stringify(obj, replacer)
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
/**
|
|
238
|
-
* Sets the value at a specified path of an object. If a portion of the path
|
|
239
|
-
* doesn't exist, it's created. Arrays are created for missing index properties
|
|
240
|
-
* while objects are created for all other missing properties. This function
|
|
241
|
-
* mutates the object.
|
|
242
|
-
*
|
|
243
|
-
* This is similar to Lodash's `_.set`.
|
|
244
|
-
*
|
|
245
|
-
* @example
|
|
246
|
-
* const object = { 'a': [{ 'b': { 'c': 3 } }] };
|
|
247
|
-
* set(object, 'a.0.b.d', 4);
|
|
248
|
-
* // object is now { 'a': [{ 'b': { 'c': 3, 'd': 4 } }] }
|
|
249
|
-
*
|
|
250
|
-
* set(object, 'x.0.y', 5);
|
|
251
|
-
* // object is now { 'a': [...], 'x': [{ 'y': 5 }] }
|
|
252
|
-
*
|
|
253
|
-
* @param {Object} obj - The object to modify.
|
|
254
|
-
* @param {string} path - The path of the property to set.
|
|
255
|
-
* @param {*} value - The value to set.
|
|
256
|
-
* @returns {Object} Returns the modified object.
|
|
257
|
-
*/
|
|
258
|
-
export function set(obj, path, value) {
|
|
259
|
-
if (!path) return obj
|
|
260
|
-
|
|
261
|
-
const keys = path.split(".")
|
|
262
|
-
let current = obj
|
|
263
|
-
|
|
264
|
-
for (let i = 0; i < keys.length - LAST_KEY_OFFSET; i++) {
|
|
265
|
-
const key = keys[i]
|
|
266
|
-
const nextKey = keys[i + NEXT_KEY_OFFSET]
|
|
267
|
-
|
|
268
|
-
// Create missing intermediate objects
|
|
269
|
-
if (!(key in current) || typeof current[key] !== "object") {
|
|
270
|
-
// Create array if next key is a number, object otherwise
|
|
271
|
-
current[key] = /^\d+$/.test(nextKey) ? [] : {}
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
current = current[key]
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
current[keys[keys.length - LAST_KEY_OFFSET]] = value
|
|
278
|
-
return obj
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
/**
|
|
282
|
-
* Converts an object or array to a formatted string representation.
|
|
283
|
-
*
|
|
284
|
-
* @param {*} obj - The object or array to convert.
|
|
285
|
-
* @param {number} [indentationLevel=INITIAL_LEVEL] - The current indentation level (used for nested structures).
|
|
286
|
-
* @returns {string} A string representation of the input object or array.
|
|
287
|
-
*/
|
|
288
|
-
export function toString(obj, indentationLevel = INITIAL_LEVEL) {
|
|
289
|
-
if (Array.isArray(obj)) {
|
|
290
|
-
return `[
|
|
291
|
-
${obj
|
|
292
|
-
.map(
|
|
293
|
-
(item) =>
|
|
294
|
-
" ".repeat(indentationLevel + NEXT_LEVEL) +
|
|
295
|
-
toString(item, indentationLevel + NEXT_LEVEL),
|
|
296
|
-
)
|
|
297
|
-
.join(",\n")}
|
|
298
|
-
${" ".repeat(indentationLevel)}]`
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
if (typeof obj === "object" && obj != null) {
|
|
302
|
-
return `{
|
|
303
|
-
${Object.entries(obj)
|
|
304
|
-
.map(
|
|
305
|
-
([key, value]) =>
|
|
306
|
-
`${" ".repeat(indentationLevel + NEXT_LEVEL)}${key}: ${toString(
|
|
307
|
-
value,
|
|
308
|
-
indentationLevel + NEXT_LEVEL,
|
|
309
|
-
)}`,
|
|
310
|
-
)
|
|
311
|
-
.join(",\n")}
|
|
312
|
-
${" ".repeat(indentationLevel)}}`
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
if (typeof obj === "string") {
|
|
316
|
-
return `"${obj}"`
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
return obj
|
|
320
|
-
}
|
package/src/math/quaternion.js
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @typedef {import("../../types/math").Vector3} Vector3
|
|
3
|
-
* @typedef {import("../../types/math").Quaternion} Quaternion
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { v } from "../v.js"
|
|
7
|
-
import { cos, sin } from "./trigonometry.js"
|
|
8
|
-
|
|
9
|
-
const DEFAULT_ANGLE = 0
|
|
10
|
-
const HALF = 2 // Constant representing the divisor for halving an angle.
|
|
11
|
-
// eslint-disable-next-line no-magic-numbers
|
|
12
|
-
const Y_AXIS = v(0, 1, 0) // Default axis of rotation (Y-axis).
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Computes a quaternion representing a rotation around a given axis.
|
|
16
|
-
* @param {number} [angle=0] - The angle of rotation in radians. Defaults to 0.
|
|
17
|
-
* @param {Vector3} [axis=Y_AXIS] - The axis of rotation as a 3D vector Defaults to the Y-axis.
|
|
18
|
-
* @returns {Quaternion} The quaternion as an array [w, x, y, z].
|
|
19
|
-
*/
|
|
20
|
-
export function quaternion(angle = DEFAULT_ANGLE, axis = Y_AXIS) {
|
|
21
|
-
return v(cos(angle / HALF), ...axis.map((coord) => coord * sin(angle / HALF)))
|
|
22
|
-
}
|