@inglorious/utils 3.8.0 → 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.
Files changed (67) hide show
  1. package/README.md +67 -3
  2. package/package.json +88 -12
  3. package/src/algorithms/decision-tree.js +3 -3
  4. package/src/algorithms/path-finding.js +6 -6
  5. package/src/data-structures/board.js +97 -15
  6. package/src/data-structures/index.js +1 -2
  7. package/src/data-structures/objects.js +352 -34
  8. package/src/data-structures/tree.js +1 -1
  9. package/src/functions/functions.js +168 -0
  10. package/src/functions/index.js +1 -4
  11. package/src/math/circle.js +5 -7
  12. package/src/math/index.js +0 -4
  13. package/src/math/line.js +3 -3
  14. package/src/math/point.js +10 -9
  15. package/src/math/quaternions.js +20 -4
  16. package/src/math/rectangle.js +4 -4
  17. package/src/math/segment.js +11 -5
  18. package/src/math/vectors.js +471 -65
  19. package/src/physics/acceleration.js +2 -3
  20. package/src/physics/friction.js +2 -2
  21. package/src/physics/gravity.js +2 -2
  22. package/src/physics/jump.js +0 -4
  23. package/src/physics/velocity.js +2 -3
  24. package/src/v.js +1 -1
  25. package/types/algorithms/decision-tree.d.ts +27 -0
  26. package/types/algorithms/index.d.ts +2 -0
  27. package/types/algorithms/path-finding.d.ts +69 -0
  28. package/types/data-structures/array.d.ts +56 -0
  29. package/types/data-structures/board.d.ts +121 -0
  30. package/types/data-structures/boolean.d.ts +4 -0
  31. package/types/data-structures/heap.d.ts +69 -0
  32. package/types/data-structures/index.d.ts +8 -0
  33. package/types/data-structures/objects.d.ts +237 -0
  34. package/types/data-structures/set.d.ts +4 -0
  35. package/types/data-structures/tree.d.ts +21 -0
  36. package/types/functions/functions.d.ts +57 -0
  37. package/types/functions/index.d.ts +1 -0
  38. package/types/index.d.ts +6 -4
  39. package/types/math/circle.d.ts +22 -0
  40. package/types/math/hitmask.d.ts +20 -0
  41. package/types/math/index.d.ts +14 -0
  42. package/types/math/line.d.ts +11 -0
  43. package/types/math/linear-interpolation.d.ts +2 -0
  44. package/types/math/numbers.d.ts +26 -0
  45. package/types/math/point.d.ts +25 -0
  46. package/types/math/quaternions.d.ts +10 -0
  47. package/types/math/rectangle.d.ts +36 -0
  48. package/types/math/rng.d.ts +14 -0
  49. package/types/math/segment.d.ts +23 -0
  50. package/types/math/statistics.d.ts +11 -0
  51. package/types/math/triangle.d.ts +5 -0
  52. package/types/math/trigonometry.d.ts +26 -0
  53. package/types/math/vectors.d.ts +190 -0
  54. package/types/physics/acceleration.d.ts +24 -0
  55. package/types/physics/friction.d.ts +11 -0
  56. package/types/physics/gravity.d.ts +20 -0
  57. package/types/physics/index.d.ts +5 -0
  58. package/types/physics/jump.d.ts +10 -0
  59. package/types/physics/velocity.d.ts +20 -0
  60. package/types/v.d.ts +7 -3
  61. package/src/data-structures/object.js +0 -320
  62. package/src/functions/function.js +0 -9
  63. package/src/math/quaternion.js +0 -22
  64. package/src/math/vector.js +0 -426
  65. package/types/algorithms.d.ts +0 -26
  66. package/types/data-structures.d.ts +0 -53
  67. 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
- }
@@ -1,9 +0,0 @@
1
- /**
2
- * Checks if a value is a function.
3
- *
4
- * @param {*} func - The value to check.
5
- * @returns {boolean} True if the value is a function, false otherwise.
6
- */
7
- export function isFunction(func) {
8
- return typeof func === "function"
9
- }
@@ -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
- }