@inglorious/utils 3.8.0 → 5.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 (73) hide show
  1. package/README.md +83 -3
  2. package/package.json +104 -12
  3. package/src/algorithms/decision-tree.js +3 -3
  4. package/src/algorithms/path-finding.js +6 -6
  5. package/src/data-structures/array.js +12 -0
  6. package/src/data-structures/board.js +97 -15
  7. package/src/data-structures/index.js +1 -2
  8. package/src/data-structures/object.js +164 -2
  9. package/src/data-structures/string.js +77 -0
  10. package/src/data-structures/tree.js +1 -1
  11. package/src/functions/function.js +190 -0
  12. package/src/functions/index.js +1 -4
  13. package/src/math/circle.js +5 -7
  14. package/src/math/hitmask.js +1 -1
  15. package/src/math/index.js +2 -6
  16. package/src/math/line.js +4 -4
  17. package/src/math/point.js +31 -9
  18. package/src/math/quaternion.js +19 -2
  19. package/src/math/rectangle.js +16 -4
  20. package/src/math/rng.js +5 -2
  21. package/src/math/segment.js +11 -5
  22. package/src/math/trigonometry.js +1 -1
  23. package/src/math/vector.js +288 -37
  24. package/src/physics/acceleration.js +2 -3
  25. package/src/physics/friction.js +1 -1
  26. package/src/physics/gravity.js +1 -1
  27. package/src/physics/jump.js +0 -4
  28. package/src/physics/velocity.js +2 -3
  29. package/src/v.js +1 -1
  30. package/types/algorithms/decision-tree.d.ts +27 -0
  31. package/types/algorithms/index.d.ts +2 -0
  32. package/types/algorithms/path-finding.d.ts +69 -0
  33. package/types/data-structures/array.d.ts +61 -0
  34. package/types/data-structures/board.d.ts +121 -0
  35. package/types/data-structures/boolean.d.ts +4 -0
  36. package/types/data-structures/heap.d.ts +69 -0
  37. package/types/data-structures/index.d.ts +8 -0
  38. package/types/data-structures/object.d.ts +237 -0
  39. package/types/data-structures/set.d.ts +4 -0
  40. package/types/data-structures/tree.d.ts +21 -0
  41. package/types/functions/function.d.ts +57 -0
  42. package/types/functions/index.d.ts +1 -0
  43. package/types/index.d.ts +6 -4
  44. package/types/math/circle.d.ts +22 -0
  45. package/types/math/hitmask.d.ts +20 -0
  46. package/types/math/index.d.ts +14 -0
  47. package/types/math/line.d.ts +11 -0
  48. package/types/math/linear-interpolation.d.ts +2 -0
  49. package/types/math/number.d.ts +26 -0
  50. package/types/math/point.d.ts +50 -0
  51. package/types/math/quaternion.d.ts +10 -0
  52. package/types/math/rectangle.d.ts +57 -0
  53. package/types/math/rng.d.ts +14 -0
  54. package/types/math/segment.d.ts +23 -0
  55. package/types/math/statistics.d.ts +11 -0
  56. package/types/math/triangle.d.ts +5 -0
  57. package/types/math/trigonometry.d.ts +26 -0
  58. package/types/math/vector.d.ts +219 -0
  59. package/types/physics/acceleration.d.ts +24 -0
  60. package/types/physics/friction.d.ts +11 -0
  61. package/types/physics/gravity.d.ts +20 -0
  62. package/types/physics/index.d.ts +5 -0
  63. package/types/physics/jump.d.ts +10 -0
  64. package/types/physics/velocity.d.ts +20 -0
  65. package/types/v.d.ts +7 -3
  66. package/src/data-structures/objects.js +0 -113
  67. package/src/functions/functions.js +0 -31
  68. package/src/math/quaternions.js +0 -23
  69. package/src/math/vectors.js +0 -212
  70. package/types/algorithms.d.ts +0 -26
  71. package/types/data-structures.d.ts +0 -53
  72. package/types/math.d.ts +0 -90
  73. /package/src/math/{numbers.js → number.js} +0 -0
package/README.md CHANGED
@@ -25,12 +25,43 @@ npm install @inglorious/utils
25
25
 
26
26
  Here are a few examples of how you can use the utilities in this package.
27
27
 
28
+ ### `compose`
29
+
30
+ Compose functions together from right to left.
31
+
32
+ ```javascript
33
+ import { compose } from "@inglorious/utils/functions"
34
+
35
+ const add = (a) => (b) => a + b
36
+ const multiply = (a) => (b) => a * b
37
+
38
+ const calculate = compose(
39
+ add(10), // 30 + 10 = 40
40
+ multiply(2), // 15 * 2 = 30
41
+ add(5), // 10 + 5 = 15
42
+ )
43
+
44
+ const result = calculate(10) // 40
45
+ ```
46
+
47
+ ### `debounce`
48
+
49
+ Delay a function until calls stop for a given amount of time.
50
+
51
+ ```javascript
52
+ import { debounce } from "@inglorious/utils/functions"
53
+
54
+ const debouncedSave = debounce(() => {
55
+ save()
56
+ }, 300)
57
+ ```
58
+
28
59
  ### `pipe`
29
60
 
30
61
  Compose functions together in a readable, left-to-right sequence.
31
62
 
32
63
  ```javascript
33
- import { pipe } from "@inglorious/utils/functions/functions"
64
+ import { pipe } from "@inglorious/utils/functions"
34
65
 
35
66
  const add = (a) => (b) => a + b
36
67
  const multiply = (a) => (b) => a * b
@@ -44,12 +75,24 @@ const calculate = pipe(
44
75
  const result = calculate(10) // 40
45
76
  ```
46
77
 
78
+ ### `throttle`
79
+
80
+ Run a function immediately, then suppress repeated calls until the wait time has elapsed.
81
+
82
+ ```javascript
83
+ import { throttle } from "@inglorious/utils/functions"
84
+
85
+ const throttledSave = throttle(() => {
86
+ save()
87
+ }, 300)
88
+ ```
89
+
47
90
  ### Vector Math
48
91
 
49
92
  Perform vector operations on plain objects.
50
93
 
51
94
  ```javascript
52
- import { add } from "@inglorious/utils/math/vector.js"
95
+ import { add } from "@inglorious/utils/vector.js"
53
96
 
54
97
  const position = [10, 20]
55
98
  const velocity = [2, -1]
@@ -58,17 +101,54 @@ const newPosition = add(position, velocity)
58
101
  // => [12, 19]
59
102
  ```
60
103
 
104
+ Two vectors are worth knowing by name: `ZERO_VECTOR`, with every component at zero, and
105
+ `UNIT_VECTOR`, one unit long along the x axis. The zero one is handy for naming the components
106
+ you care about, or for building a vector up from scratch:
107
+
108
+ ```javascript
109
+ import { ZERO_VECTOR } from "@inglorious/utils/math/vector.js"
110
+ import { v } from "@inglorious/utils/v.js"
111
+
112
+ const [, NO_RISE, NO_DEPTH] = ZERO_VECTOR
113
+
114
+ const position = v(10, 20, NO_DEPTH)
115
+ ```
116
+
117
+ Vectors are mutable arrays, so copy a shared vector rather than storing it where something writes
118
+ to one, such as an entity position. Copy it with `v(...ZERO_VECTOR)`: a plain spread
119
+ (`[...ZERO_VECTOR]`) gives you a new array but drops the tag that `isVector` looks for.
120
+
61
121
  ---
62
122
 
63
123
  ## API
64
124
 
65
125
  This package is designed to be used with subpath imports, which helps with tree-shaking.
66
126
 
127
+ Most modules are grouped by category:
128
+
67
129
  - **`@inglorious/utils/algorithms`**: Utilities for AI algorithms, like decision trees and A\*.
68
- - **`@inglorious/utils/functions`**: Utilities for function composition.
130
+ - **`@inglorious/utils/data-structures`**: Utilities for arrays, boards, heaps, objects, sets, strings, and trees.
69
131
  - **`@inglorious/utils/math`**: Utilities for math operations.
70
132
  - **`@inglorious/utils/physics`**: Utilities for calculations on friction, acceleration, and gravity.
71
133
 
134
+ The four largest modules are also available as top-level subpaths, so you don't need to
135
+ know whether a helper lives under `data-structures` or `math`:
136
+
137
+ - **`@inglorious/utils/functions`**: `compose`, `debounce`, `isFunction`, `pipe`, `throttle`.
138
+ - **`@inglorious/utils/object`**: Single-object helpers (`clone`, `get`, `set`, `produce`, ...) alongside multi-object helpers (`merge`, `extend`, `defaults`, ...).
139
+ - **`@inglorious/utils/quaternion`**: `quaternion` and `combine`.
140
+ - **`@inglorious/utils/vector`**: Single-vector helpers (`magnitude`, `normalize`, `rotate`, ...) alongside multi-vector helpers (`cross`, `dot`, `sum`, ...).
141
+
142
+ `divide`, `mod`, `multiply` and `power` accept either a scalar or one or more vectors:
143
+ a scalar is applied to every component, while vectors are combined component-wise.
144
+
145
+ ```javascript
146
+ import { multiply } from "@inglorious/utils/vector.js"
147
+
148
+ multiply([1, 2, 3], 2) // => [2, 4, 6]
149
+ multiply([1, 2, 3], [4, 5, 6]) // => [4, 10, 18]
150
+ ```
151
+
72
152
  ---
73
153
 
74
154
  ## License
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@inglorious/utils",
3
- "version": "3.8.0",
3
+ "version": "5.0.0",
4
4
  "description": "A set of general-purpose utility functions designed with functional programming principles in mind.",
5
- "author": "IceOnFire <antony.mistretta@gmail.com> (https://ingloriouscoderz.it)",
5
+ "author": "Matteo Antony Mistretta <antony.mistretta@gmail.com> (https://ingloriouscoderz.it)",
6
6
  "license": "MIT",
7
7
  "repository": {
8
8
  "type": "git",
@@ -26,13 +26,105 @@
26
26
  "types": "./types/index.d.ts",
27
27
  "import": "./src/index.js"
28
28
  },
29
- "./data-structures/string.js": {
30
- "types": "./types/data-structures/string.d.ts",
31
- "import": "./src/data-structures/string.js"
29
+ "./array.js": {
30
+ "types": "./types/data-structures/array.d.ts",
31
+ "import": "./src/data-structures/array.js"
32
32
  },
33
- "./*": {
34
- "types": "./types/*.d.ts",
35
- "import": "./src/*"
33
+ "./array": {
34
+ "types": "./types/data-structures/array.d.ts",
35
+ "import": "./src/data-structures/array.js"
36
+ },
37
+ "./algorithms": {
38
+ "types": "./types/algorithms/index.d.ts",
39
+ "import": "./src/algorithms/index.js"
40
+ },
41
+ "./algorithms/*.js": {
42
+ "types": "./types/algorithms/*.d.ts",
43
+ "import": "./src/algorithms/*.js"
44
+ },
45
+ "./algorithms/*": {
46
+ "types": "./types/algorithms/*.d.ts",
47
+ "import": "./src/algorithms/*.js"
48
+ },
49
+ "./data-structures": {
50
+ "types": "./types/data-structures/index.d.ts",
51
+ "import": "./src/data-structures/index.js"
52
+ },
53
+ "./data-structures/*.js": {
54
+ "types": "./types/data-structures/*.d.ts",
55
+ "import": "./src/data-structures/*.js"
56
+ },
57
+ "./data-structures/*": {
58
+ "types": "./types/data-structures/*.d.ts",
59
+ "import": "./src/data-structures/*.js"
60
+ },
61
+ "./function.js": {
62
+ "types": "./types/functions/function.d.ts",
63
+ "import": "./src/functions/function.js"
64
+ },
65
+ "./function": {
66
+ "types": "./types/functions/function.d.ts",
67
+ "import": "./src/functions/function.js"
68
+ },
69
+ "./functions": {
70
+ "types": "./types/functions/index.d.ts",
71
+ "import": "./src/functions/index.js"
72
+ },
73
+ "./math": {
74
+ "types": "./types/math/index.d.ts",
75
+ "import": "./src/math/index.js"
76
+ },
77
+ "./math/*.js": {
78
+ "types": "./types/math/*.d.ts",
79
+ "import": "./src/math/*.js"
80
+ },
81
+ "./math/*": {
82
+ "types": "./types/math/*.d.ts",
83
+ "import": "./src/math/*.js"
84
+ },
85
+ "./physics": {
86
+ "types": "./types/physics/index.d.ts",
87
+ "import": "./src/physics/index.js"
88
+ },
89
+ "./physics/*.js": {
90
+ "types": "./types/physics/*.d.ts",
91
+ "import": "./src/physics/*.js"
92
+ },
93
+ "./physics/*": {
94
+ "types": "./types/physics/*.d.ts",
95
+ "import": "./src/physics/*.js"
96
+ },
97
+ "./object.js": {
98
+ "types": "./types/data-structures/object.d.ts",
99
+ "import": "./src/data-structures/object.js"
100
+ },
101
+ "./object": {
102
+ "types": "./types/data-structures/object.d.ts",
103
+ "import": "./src/data-structures/object.js"
104
+ },
105
+ "./quaternion.js": {
106
+ "types": "./types/math/quaternion.d.ts",
107
+ "import": "./src/math/quaternion.js"
108
+ },
109
+ "./quaternion": {
110
+ "types": "./types/math/quaternion.d.ts",
111
+ "import": "./src/math/quaternion.js"
112
+ },
113
+ "./vector.js": {
114
+ "types": "./types/math/vector.d.ts",
115
+ "import": "./src/math/vector.js"
116
+ },
117
+ "./vector": {
118
+ "types": "./types/math/vector.d.ts",
119
+ "import": "./src/math/vector.js"
120
+ },
121
+ "./v.js": {
122
+ "types": "./types/v.d.ts",
123
+ "import": "./src/v.js"
124
+ },
125
+ "./v": {
126
+ "types": "./types/v.d.ts",
127
+ "import": "./src/v.js"
36
128
  }
37
129
  },
38
130
  "files": [
@@ -45,10 +137,10 @@
45
137
  },
46
138
  "sideEffects": false,
47
139
  "devDependencies": {
48
- "prettier": "^3.6.2",
49
- "vite": "^7.1.3",
50
- "vitest": "^1.6.1",
51
- "@inglorious/eslint-config": "1.1.2"
140
+ "@inglorious/eslint-config": "1.1.2",
141
+ "prettier": "^3.9.6",
142
+ "vite": "^8.2.2",
143
+ "vitest": "^5.0.0"
52
144
  },
53
145
  "engines": {
54
146
  "node": ">= 22"
@@ -1,7 +1,7 @@
1
1
  /**
2
- * @typedef {import("../../types/algorithms").Conditions} Conditions
3
- * @typedef {import("../../types/algorithms").Outcome} Outcome
4
- * @typedef {import("../../types/algorithms").DecisionTree} DecisionTree
2
+ * @typedef {import("../../types/algorithms/decision-tree").Conditions} Conditions
3
+ * @typedef {import("../../types/algorithms/decision-tree").Outcome} Outcome
4
+ * @typedef {import("../../types/algorithms/decision-tree").DecisionTree} DecisionTree
5
5
  */
6
6
 
7
7
  /**
@@ -1,11 +1,11 @@
1
1
  /**
2
- * @typedef {import("../../types/data-structures").Node} Node
3
- * @typedef {import("../../types/data-structures").Graph} Graph
2
+ * @typedef {import("../../types/algorithms/path-finding").Node} Node
3
+ * @typedef {import("../../types/algorithms/path-finding").Graph} Graph
4
+ * @typedef {import("../../types/math/vector").Vector2} Vector2
4
5
  */
5
6
 
6
7
  import { contains, push, remove, root } from "../data-structures/heap.js"
7
- import { abs, magnitude } from "../math/vector.js"
8
- import { subtract } from "../math/vectors.js"
8
+ import { abs, magnitude, subtract } from "../math/vector.js"
9
9
 
10
10
  const NO_COST = 0
11
11
 
@@ -32,7 +32,7 @@ export const eucledianDistance = (a, b) =>
32
32
  *
33
33
  * @param {Node} a - The first node.
34
34
  * @param {Node} b - The second node.
35
- * @returns {number} - The Manhattan distance between the two nodes.
35
+ * @returns {Vector2} The component-wise Manhattan distance between the two nodes.
36
36
  */
37
37
  export const manhattanDistance = (a, b) => abs(subtract(a.position, b.position))
38
38
 
@@ -61,7 +61,7 @@ const compareTotalCost = (a, b) => b.totalCost - a.totalCost
61
61
  * @param {string} start - The ID of the start node.
62
62
  * @param {string} end - The ID of the end node.
63
63
  * @param {(a: Node, b: Node) => number} [heuristic=eucledianDistance] - The heuristic function to estimate the cost.
64
- * @returns {string[]} - An array of node IDs representing the shortest path.
64
+ * @returns {string[]|undefined} - The node IDs representing the shortest path, or `undefined` if no path exists.
65
65
  */
66
66
  export function findPath(graph, start, end, heuristic = eucledianDistance) {
67
67
  const { nodes, arcs } = adaptGraph(graph)
@@ -22,6 +22,18 @@ export function contains(arr, item) {
22
22
  return arr.includes(item)
23
23
  }
24
24
 
25
+ /**
26
+ * The index `step` places along a list of `length`, wrapping round at either end.
27
+ *
28
+ * @param {number} index - Where to start from.
29
+ * @param {number} length - How long the list is.
30
+ * @param {number} step - How far to move. Negative steps move backwards.
31
+ * @returns {number} - The index landed on, always within the list.
32
+ */
33
+ export function cycleIndex(index, length, step) {
34
+ return (((index + step) % length) + length) % length
35
+ }
36
+
25
37
  /**
26
38
  * Ensures that the given value is an array. If it's not an array, it wraps it in one.
27
39
  *
@@ -11,24 +11,55 @@ const DEFAULT_FILLER = () => null
11
11
  */
12
12
  const DEFAULT_CELL_TO_STRING = (cell) => `${cell}`
13
13
 
14
+ /**
15
+ * Default predicate that matches every neighboring cell.
16
+ * @returns {boolean} Always true.
17
+ */
18
+ const DEFAULT_NEIGHBOR_PREDICATE = () => true
19
+
14
20
  const FIRST_ROW = 0
15
21
  const FIRST_COLUMN = 0
16
22
  const LAST_ROW_OFFSET = 1
17
23
  const LAST_COLUMN_OFFSET = 1
18
- const MOVE_DOWN = 1
19
- const MOVE_LEFT = -1
20
- const MOVE_RIGHT = 1
21
- const MOVE_UP = -1
24
+ const DOWN = 1
25
+ const LEFT = -1
26
+ const RIGHT = 1
27
+ const UP = -1
28
+ const CENTER = 0
29
+
30
+ const BOTH = "both"
31
+ const HORIZONTAL = "horizontal"
32
+ const NO_WRAP = undefined
33
+ const VERTICAL = "vertical"
34
+
35
+ const NEIGHBOR_OFFSETS = [
36
+ [UP, LEFT],
37
+ [UP, CENTER],
38
+ [UP, RIGHT],
39
+ [CENTER, LEFT],
40
+ [CENTER, RIGHT],
41
+ [DOWN, LEFT],
42
+ [DOWN, CENTER],
43
+ [DOWN, RIGHT],
44
+ ]
22
45
 
23
46
  /**
24
- * Calculates the index in a one-dimensional array for given row and column.
25
- * @param {number} row - The row index.
26
- * @param {number} column - The column index.
27
- * @param {number} columns - The total number of columns.
28
- * @returns {number} The calculated index.
47
+ * Counts the neighboring cells that satisfy a predicate.
48
+ * @param {Array} cells - The board cells.
49
+ * @param {[number, number]} coords - The coordinates [row, column].
50
+ * @param {[number, number]} size - Array containing the number of rows and columns.
51
+ * @param {Object} [options] - Neighbor options.
52
+ * @param {Function} [options.predicate=DEFAULT_NEIGHBOR_PREDICATE] - The predicate applied to each neighboring cell.
53
+ * @param {"horizontal" | "vertical" | "both"} [options.wrap=undefined] - The axes that wrap around board edges.
54
+ * @returns {number} The number of matching neighboring cells.
29
55
  */
30
- function getIndex(row, column, columns) {
31
- return row * columns + column
56
+ export function countNeighbors(cells, coords, size, options = {}) {
57
+ const { predicate = DEFAULT_NEIGHBOR_PREDICATE, wrap = NO_WRAP } = options
58
+ const [, columns] = size
59
+
60
+ return neighbors(coords, size, { wrap }).filter(([row, column]) =>
61
+ predicate(cells[getIndex(row, column, columns)]),
62
+ ).length
32
63
  }
33
64
 
34
65
  /**
@@ -56,7 +87,7 @@ export function down([i, j], [rows]) {
56
87
  if (i === rows - LAST_ROW_OFFSET) {
57
88
  throw new Error()
58
89
  }
59
- return [i + MOVE_DOWN, j]
90
+ return [i + DOWN, j]
60
91
  }
61
92
 
62
93
  /**
@@ -79,6 +110,17 @@ export function downRight(coords, size) {
79
110
  return down(right(coords, size), size)
80
111
  }
81
112
 
113
+ /**
114
+ * Calculates the index in a one-dimensional array for given row and column.
115
+ * @param {number} row - The row index.
116
+ * @param {number} column - The column index.
117
+ * @param {number} columns - The total number of columns.
118
+ * @returns {number} The calculated index.
119
+ */
120
+ export function getIndex(row, column, columns) {
121
+ return row * columns + column
122
+ }
123
+
82
124
  /**
83
125
  * Moves the given coordinates one step left.
84
126
  * @param {[number, number]} coords - The current coordinates [row, column].
@@ -89,7 +131,36 @@ export function left([i, j]) {
89
131
  if (j === FIRST_COLUMN) {
90
132
  throw new Error()
91
133
  }
92
- return [i, j + MOVE_LEFT]
134
+ return [i, j + LEFT]
135
+ }
136
+
137
+ /**
138
+ * Returns the coordinates neighboring the given coordinates that fall within the board.
139
+ * @param {[number, number]} coords - The coordinates [row, column].
140
+ * @param {[number, number]} size - Array containing the number of rows and columns.
141
+ * @param {Object} [options] - Neighbor options.
142
+ * @param {"horizontal" | "vertical" | "both"} [options.wrap=undefined] - The axes that wrap around board edges. "horizontal" wraps the column axis, "vertical" wraps the row axis, and "both" wraps each axis independently.
143
+ * @returns {[number, number][]} The neighboring coordinates within the board.
144
+ */
145
+ export function neighbors([i, j], [rows, columns], options = {}) {
146
+ const { wrap = NO_WRAP } = options
147
+ const shouldWrapRows = wrap === BOTH || wrap === VERTICAL
148
+ const shouldWrapColumns = wrap === BOTH || wrap === HORIZONTAL
149
+
150
+ return NEIGHBOR_OFFSETS.map(([rowOffset, columnOffset]) => {
151
+ const row = shouldWrapRows ? wrapIndex(i + rowOffset, rows) : i + rowOffset
152
+ const column = shouldWrapColumns
153
+ ? wrapIndex(j + columnOffset, columns)
154
+ : j + columnOffset
155
+
156
+ return [row, column]
157
+ }).filter(
158
+ ([row, column]) =>
159
+ row >= FIRST_ROW &&
160
+ row < rows &&
161
+ column >= FIRST_COLUMN &&
162
+ column < columns,
163
+ )
93
164
  }
94
165
 
95
166
  /**
@@ -103,7 +174,7 @@ export function right([i, j], [, columns]) {
103
174
  if (j === columns - LAST_COLUMN_OFFSET) {
104
175
  throw new Error()
105
176
  }
106
- return [i, j + MOVE_RIGHT]
177
+ return [i, j + RIGHT]
107
178
  }
108
179
 
109
180
  /**
@@ -135,7 +206,7 @@ export function up([i, j]) {
135
206
  if (i === FIRST_ROW) {
136
207
  throw new Error()
137
208
  }
138
- return [i + MOVE_UP, j]
209
+ return [i + UP, j]
139
210
  }
140
211
 
141
212
  /**
@@ -157,3 +228,14 @@ export function upLeft(coords, size) {
157
228
  export function upRight(coords, size) {
158
229
  return up(right(coords, size), size)
159
230
  }
231
+
232
+ /**
233
+ * Normalizes an index into a wrapping range.
234
+ * @param {number} index - The index to normalize.
235
+ * @param {number} length - The range length.
236
+ * @returns {number} The normalized index.
237
+ */
238
+ function wrapIndex(index, length) {
239
+ const remainder = index % length
240
+ return remainder < FIRST_ROW ? remainder + length : remainder
241
+ }
@@ -3,9 +3,8 @@ import * as board from "./board.js"
3
3
  import * as boolean from "./boolean.js"
4
4
  import * as heap from "./heap.js"
5
5
  import * as object from "./object.js"
6
- import * as objects from "./objects.js"
7
6
  import * as set from "./set.js"
8
7
  import * as string from "./string.js"
9
8
  import * as tree from "./tree.js"
10
9
 
11
- export { array, board, boolean, heap, object, objects, set, string, tree }
10
+ export { array, board, boolean, heap, object, set, string, tree }