@hyperfrontend/list-utils 0.0.5 → 0.1.1

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/CHANGELOG.md CHANGED
@@ -2,6 +2,22 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [0.1.1](https://github.com/AndrewRedican/hyperfrontend/compare/29dc54d58c2b3c8b8dd35f7c546ebc6cd9191f6e...adf0a4f77dece2be855e7ab88185a4fe84e7b16b) - 2026-09-14
6
+
7
+ ### Bug Fixes
8
+
9
+ - accept arrays, functions and class instances in fifo and lifo lists
10
+
11
+ ## [0.1.0](https://github.com/AndrewRedican/hyperfrontend/compare/5f116abb8ba6355dfb283fa03b7481e5eb029480...cc16961a470190848f71a7cce41f7377bc4511a4) - 2026-08-25
12
+
13
+ ### Breaking Changes
14
+
15
+ - **BREAKING** type fifo pull as T | undefined, reword throws
16
+
17
+ ### Bug Fixes
18
+
19
+ - **BREAKING** type fifo pull as T | undefined, reword throws
20
+
5
21
  ## [0.0.5](https://github.com/AndrewRedican/hyperfrontend/compare/c8db08be8b183addd26caf81fdd17fb3693f296f...466c0388c4cd516b9c704214140b4df1004098e6) - 2026-06-23
6
22
 
7
23
  ### Other
package/README.md CHANGED
@@ -1,4 +1,8 @@
1
- # @hyperfrontend/list-utils
1
+ <p align="center">
2
+ <a href="https://www.hyperfrontend.dev/docs/libraries/utils/list/">
3
+ <img width="640" height="180" src="https://www.hyperfrontend.dev/media/banner-list-utils/banner.gif" alt="@hyperfrontend/list-utils">
4
+ </a>
5
+ </p>
2
6
 
3
7
  <p align="center">
4
8
  <a href="https://github.com/AndrewRedican/hyperfrontend/actions/workflows/ci-lib-list-utils.yml">
@@ -33,9 +37,16 @@
33
37
  <img src="https://img.shields.io/badge/tree%20shakeable-%E2%9C%93-success?style=flat-square" alt="Tree Shakeable">
34
38
  </p>
35
39
 
40
+ <p align="center">
41
+ <a href="https://www.hyperfrontend.dev/docs/libraries/utils/list/">
42
+ <img width="640" height="360" src="https://www.hyperfrontend.dev/media/list-utils-order/hero.gif" alt="A tube open at both ends and a cup open only at the top, with the same three numbered discs dropped into each; three pulls take the discs out, the tube from its bottom and the cup from its top, and the exit rows read 1 2 3 under the tube and 3 2 1 beside the cup">
43
+ </a>
44
+ </p>
45
+
36
46
  Purpose-built collection utilities for queue management, filtering, and iteration patterns.
37
47
 
38
48
  • 👉 See [**documentation**](https://www.hyperfrontend.dev/docs/libraries/utils/list/)
49
+ • 👉 See [**guides & tutorials**](https://www.hyperfrontend.dev/docs/guides/?package=%40hyperfrontend%2Flist-utils)
39
50
 
40
51
  ## What is @hyperfrontend/list-utils?
41
52
 
@@ -45,26 +56,26 @@ The library enforces immutability through frozen interfaces while maintaining hi
45
56
 
46
57
  ### Key Features
47
58
 
48
- - **FIFO and LIFO queues** with type-safe object tracking
49
- - **Value picker** for cyclical iteration (ideal for round-robin patterns)
50
- - **String sanitization** utilities (dedupe, trim, filter empty)
51
- - **Range generation** for loop-free number sequences
52
- - **Map utilities** for common Map operations
59
+ - **[FIFO and LIFO queues](https://www.hyperfrontend.dev/docs/libraries/utils/list/#api-createFifoList)** with type-safe object tracking
60
+ - **[Value picker](https://www.hyperfrontend.dev/docs/libraries/utils/list/#api-createValuePicker)** for cyclical iteration (ideal for round-robin patterns)
61
+ - **[String sanitization](https://www.hyperfrontend.dev/docs/libraries/utils/list/#api-uniqueStrings)** utilities (dedupe, trim, filter empty)
62
+ - **[Range generation](https://www.hyperfrontend.dev/docs/libraries/utils/list/#api-createRange)** for loop-free number sequences
63
+ - **[Map utilities](https://www.hyperfrontend.dev/docs/libraries/utils/list/#api-getLastKeyInMap)** for common Map operations
53
64
  - **Zero dependencies** - Self-contained implementation with no third-party runtime dependencies
54
65
 
55
66
  ### Architecture Highlights
56
67
 
57
- Queue implementations return frozen objects to prevent external mutation while using native `Set` internally for optimal performance. Object-only restriction on queues prevents reference comparison issues with primitives.
68
+ Both queue kinds hold object references only: pushing a primitive throws at runtime, not just at compile time. Membership is reference identity, so two structurally identical objects are two separate entries, and `has()` and `remove()` need the same reference you pushed.
58
69
 
59
70
  ## Why Use @hyperfrontend/list-utils?
60
71
 
61
72
  ### Prevents Queue Bugs in Event-Driven Systems
62
73
 
63
- Native arrays don't enforce uniqueness, making it easy to accidentally register the same event handler, task, or subscription multiple times. FIFO/LIFO lists automatically reject duplicates based on reference equality, eliminating a common source of memory leaks and duplicate processing in event loops, job queues, and observer patterns.
74
+ Native arrays don't enforce uniqueness, making it easy to accidentally register the same event handler, task, or subscription multiple times. Both list kinds reject duplicates based on reference equality, eliminating a common source of memory leaks and duplicate processing in event loops, job queues, and observer patterns. A FIFO list throws on a duplicate push; a LIFO list ignores it.
64
75
 
65
76
  ### Simplifies Round-Robin and Cyclical Patterns
66
77
 
67
- The value picker solves the boilerplate problem of cycling through options (load balancer endpoints, color schemes, retry strategies). No manual index tracking or modulo math—just call `next()`. Particularly useful for testing scenarios where you need predictable value rotation.
78
+ The value picker solves the boilerplate problem of cycling through options (load balancer endpoints, color schemes, retry strategies). No manual index tracking or modulo math, just call `next()`. Particularly useful for testing scenarios where you need predictable value rotation.
68
79
 
69
80
  ### Type-Safe String Sanitization
70
81
 
@@ -89,7 +100,7 @@ import { createFifoList, createValuePicker, nonEmptyStrings, uniqueStrings } fro
89
100
  const taskQueue = createFifoList<{ id: string; execute: () => void }>()
90
101
  taskQueue.push({ id: 'task1', execute: () => console.log('Task 1') })
91
102
  taskQueue.push({ id: 'task2', execute: () => console.log('Task 2') })
92
- const nextTask = taskQueue.pull() // Gets task1 (first in)
103
+ const nextTask = taskQueue.pull() // Gets task1 (first in), or undefined once the queue is drained
93
104
 
94
105
  // Round-robin value picker
95
106
  const colorPicker = createValuePicker(['red', 'blue', 'green'])
@@ -98,40 +109,28 @@ colorPicker.next() // 'blue'
98
109
  colorPicker.next() // 'green'
99
110
  colorPicker.next() // 'red' (cycles back)
100
111
 
101
- // String sanitization
112
+ // String sanitization: blanks are dropped, survivors keep their original padding
102
113
  const userInputs = [' hello ', '', 'world', null, 'hello', ' ', 'world']
103
- const cleaned = uniqueStrings(nonEmptyStrings(userInputs)) // ['hello', 'world']
114
+ const cleaned = uniqueStrings(nonEmptyStrings(userInputs)) // [' hello ', 'world', 'hello']
104
115
  ```
105
116
 
106
117
  ## API Overview
107
118
 
108
- ### Queue Management
119
+ Two ordered collections plus a few standalone helpers; the collections are the place to start. [`createFifoList`](https://www.hyperfrontend.dev/docs/libraries/utils/list/#api-createFifoList) and [`createLifoList`](https://www.hyperfrontend.dev/docs/libraries/utils/list/#api-createLifoList) each take no arguments, are generic over an object type, and return a frozen instance with the same fixed method surface: [`push`](https://www.hyperfrontend.dev/docs/libraries/utils/list/#api-FifoList), [`pull`](https://www.hyperfrontend.dev/docs/libraries/utils/list/#api-FifoList), [`map`](https://www.hyperfrontend.dev/docs/libraries/utils/list/#api-FifoList), [`forEach`](https://www.hyperfrontend.dev/docs/libraries/utils/list/#api-FifoList), [`remove`](https://www.hyperfrontend.dev/docs/libraries/utils/list/#api-FifoList), [`has`](https://www.hyperfrontend.dev/docs/libraries/utils/list/#api-FifoList), [`size`](https://www.hyperfrontend.dev/docs/libraries/utils/list/#api-FifoList) and [`clear`](https://www.hyperfrontend.dev/docs/libraries/utils/list/#api-FifoList). Choosing one factory over the other decides which end `pull()` reads from and nothing else about the surrounding code. They diverge on one point, deliberately: pushing an item a FIFO list already holds throws, surfacing a queue that would otherwise take the same job twice, whereas a LIFO list ignores the duplicate and leaves the item where it already was.
109
120
 
110
- - **`createFifoList<T>()`** - First-in-first-out queue with reference uniqueness
111
- - **`createLifoList<T>()`** - Last-in-first-out stack with reference uniqueness
121
+ Both are backed by a `Set` of the references you pushed, which has two consequences to know before reaching for either. A primitive is rejected at runtime, not only by the type parameter. And membership is reference identity, so two structurally identical objects are two entries, and `has()` and `remove()` want back the exact reference you handed over.
112
122
 
113
- ### Iteration Utilities
123
+ The helpers are independent of the lists and of each other. [`createValuePicker`](https://www.hyperfrontend.dev/docs/libraries/utils/list/#api-createValuePicker) wraps a non-empty string array in a `current()` and `next()` pair that cycles forever, while [`createRange`](https://www.hyperfrontend.dev/docs/libraries/utils/list/#api-createRange) returns an inclusive run of numbers. For string arrays, [`nonEmptyStrings`](https://www.hyperfrontend.dev/docs/libraries/utils/list/#api-nonEmptyStrings) drops null, undefined, empty and whitespace-only entries but returns the survivors exactly as they arrived: it tests `value.trim()`, it does not trim, so padded values come through padded and [`uniqueStrings`](https://www.hyperfrontend.dev/docs/libraries/utils/list/#api-uniqueStrings) then dedupes on exact string equality, which leaves `' hello '` and `'hello'` as two distinct results. The last helper, [`getLastKeyInMap`](https://www.hyperfrontend.dev/docs/libraries/utils/list/#api-getLastKeyInMap), reads the most recently inserted key of a `Map`.
114
124
 
115
- - **`createValuePicker(values)`** - Cyclical iterator for round-robin patterns
116
- - **`createRange(start, end)`** - Generate number arrays without loops
117
-
118
- ### String Utilities
119
-
120
- - **`nonEmptyStrings(values)`** - Filter null/undefined/empty/whitespace strings
121
- - **`uniqueStrings(values)`** - Remove duplicates while preserving order
122
-
123
- ### Map Helpers
124
-
125
- - **`getLastKeyInMap(map)`** - Retrieve the last inserted key from a Map
125
+ Every signature, type parameter and thrown error is in the [API reference](https://www.hyperfrontend.dev/docs/libraries/utils/list/#api-reference).
126
126
 
127
127
  ## Compatibility
128
128
 
129
- | Platform | Support |
130
- | ----------------------------- | :-----: |
131
- | Browser | ✅ |
132
- | Node.js | ✅ |
133
- | Web Workers | ✅ |
134
- | Deno, Bun, Cloudflare Workers | ✅ |
129
+ <p align="center">
130
+ <a href="https://www.hyperfrontend.dev/docs/libraries/utils/list/#compatibility">
131
+ <img width="640" height="150" src="https://www.hyperfrontend.dev/media/runtimes-list-utils/runtimes.png" alt="Runs in Node.js 18 or later, evergreen browsers and web workers">
132
+ </a>
133
+ </p>
135
134
 
136
135
  ### Output Formats
137
136
 
@@ -156,7 +155,7 @@ const cleaned = uniqueStrings(nonEmptyStrings(userInputs)) // ['hello', 'world']
156
155
  </script>
157
156
  ```
158
157
 
159
- **Global variable:** `HyperfrontendListUtils`
158
+ **Global variable:** [`HyperfrontendListUtils`](https://www.hyperfrontend.dev/docs/libraries/utils/list/)
160
159
 
161
160
  ## Part of hyperfrontend
162
161
 
package/SECURITY.md CHANGED
@@ -1,5 +1,28 @@
1
1
  # Security Policy
2
2
 
3
+ ## The Security Model
4
+
5
+ Before reporting or reviewing, read the model this project is built on:
6
+ **[Security Model](https://www.hyperfrontend.dev/docs/core-concepts/security)**. It is the canonical
7
+ statement of what hyperfrontend defends against and what it does not, and it is the reference every
8
+ other security claim in these docs points back to. In short:
9
+
10
+ - **The named adversary is co-resident script**: an analytics snippet, tag manager, compromised
11
+ dependency, or unknown page that embeds a feature URL. A host that deliberately installs a feature
12
+ is trusting it, the way it trusts any dependency; the controls exist to bound a trusted
13
+ feature's bad day, not to treat its authors as hostile.
14
+ - **Origin checks authenticate rooms, not speakers.** Once arbitrary script runs inside a page, no
15
+ message check distinguishes it from the application. Threats inside a page need Content Security
16
+ Policy, Trusted Types, dependency provenance, and server-side authorisation. That is a different
17
+ treatment, deliberately outside this model.
18
+ - **Three parties carry the security of an integration.** The browser enforces document isolation
19
+ and the frame's capability attributes; the protocol enforces the relationship (pinned
20
+ counterparts, gated handshake, validated payloads, versioned contracts, an optional encrypted
21
+ envelope); and **you** decide authorisation: `frame-ancestors`, backend checks, HTTPS, the
22
+ envelope you choose, and the containment posture you set.
23
+
24
+ A vulnerability report is most useful when it names which of those three the issue defeats.
25
+
3
26
  ## Reporting a Vulnerability
4
27
 
5
28
  We take the security of hyperfrontend seriously. If you discover a security vulnerability, please help us protect our users by following responsible disclosure practices.
@@ -58,14 +81,30 @@ Thank you for helping keep hyperfrontend and its users safe!
58
81
 
59
82
  ## Security Best Practices
60
83
 
61
- When using hyperfrontend in your applications:
62
-
63
- 1. **Keep Dependencies Updated**: Regularly update to the latest version to receive security patches
64
- 2. **Content Security Policy**: Implement appropriate CSP headers when embedding features
65
- 3. **Input Validation**: Validate and sanitize all data passed between features
66
- 4. **Origin Verification**: Always verify the origin of messages in cross-frame communication
67
- 5. **Authentication**: Implement proper authentication and authorization for sensitive features
68
- 6. **HTTPS**: Always serve hyperfrontend features over HTTPS in production
84
+ These are the decisions the SDK cannot make for you. Everything the protocol already enforces —
85
+ origin pinning, window binding, instance identity, the gated handshake, payload validation on both
86
+ ends — is on by default and is not something you should be re-implementing by hand.
87
+
88
+ 1. **Restrict who may embed the feature.** Send
89
+ `Content-Security-Policy: frame-ancestors <hosts>` on the response that serves the feature
90
+ document. Origin pinning keeps a conversation consistent; only `frame-ancestors` decides whether
91
+ a page was ever allowed to frame you.
92
+ 2. **Authorise on the server.** A message that crossed the boundary is not an authorised operation.
93
+ Protected work needs credentials the feature's own backend validates.
94
+ 3. **Choose the envelope deliberately.** `v2` with a pre-shared key is the confidentiality control;
95
+ `v1` is time-window obfuscation and buys deterrence only. Provision and rotate the `v2` key
96
+ yourself; a key is never baked into a built artifact. A handshake that cannot agree on an
97
+ encrypted transport falls back to plaintext; where that would be unacceptable, drive
98
+ `@hyperfrontend/nexus` directly and set `security.mode: 'fail-closed'` on the channel so the
99
+ connection is denied instead.
100
+ 4. **Declare schemas and a contract version.** Actions without a schema pass unvalidated, and a side
101
+ without a version always passes the compatibility gate. Both are how drift is caught early.
102
+ 5. **Grant capability narrowly.** Delegate only the Permissions-Policy features the integration
103
+ needs, and price a `sandbox` posture against what the product actually requires.
104
+ 6. **Serve everything over HTTPS**, host and feature alike.
105
+ 7. **Keep dependencies updated** on both sides of the boundary, and pair that with the page-integrity
106
+ controls this model deliberately leaves to you: Content Security Policy, Trusted Types,
107
+ Subresource Integrity, and dependency provenance.
69
108
 
70
109
  ## Security Updates
71
110
 
@@ -73,10 +112,6 @@ Security updates will be released as patch versions and documented in the [CHANG
73
112
 
74
113
  ## Supported Versions
75
114
 
76
- We currently provide security updates for:
77
-
78
- | Version | Supported |
79
- | ------- | ------------------ |
80
- | 0.0.x | :white_check_mark: |
81
-
82
- As the project matures, we will update this table to reflect our long-term support policy.
115
+ Security updates are provided for the latest published version of each `@hyperfrontend/*` package.
116
+ Older releases receive no backports. A long-term support policy will replace this section once the
117
+ packages settle on a stable release cadence.
@@ -1,7 +1,5 @@
1
1
  'use strict';
2
2
 
3
3
  const _Array = globalThis.Array;
4
- const isArray = _Array.isArray;
5
4
  const from = _Array.from;
6
5
  exports.from = from;
7
- exports.isArray = isArray;
@@ -1,5 +1,4 @@
1
1
  const _Array = globalThis.Array;
2
- const isArray = _Array.isArray;
3
2
  const from = _Array.from;
4
3
 
5
- export { from, isArray };
4
+ export { from };
@@ -2,6 +2,4 @@
2
2
 
3
3
  const _Object = globalThis.Object;
4
4
  const freeze = _Object.freeze;
5
- const keys = _Object.keys;
6
5
  exports.freeze = freeze;
7
- exports.keys = keys;
@@ -1,5 +1,4 @@
1
1
  const _Object = globalThis.Object;
2
2
  const freeze = _Object.freeze;
3
- const keys = _Object.keys;
4
3
 
5
- export { freeze, keys };
4
+ export { freeze };
@@ -1,143 +1,29 @@
1
1
  var HyperfrontendListUtils = (function (exports) {
2
2
  'use strict';
3
3
 
4
- /**
5
- * Safe copies of Array built-in static methods.
6
- *
7
- * These references are captured at module initialization time to protect against
8
- * prototype pollution attacks. Import only what you need for tree-shaking.
9
- *
10
- * @module @hyperfrontend/immutable-api-utils/built-in-copy/array
11
- */
12
4
  const _Array = globalThis.Array;
13
- /**
14
- * (Safe copy) Determines whether the passed value is an Array.
15
- */
16
- const isArray = _Array.isArray;
17
- /**
18
- * (Safe copy) Creates an array from an array-like or iterable object.
19
- */
20
5
  const from = _Array.from;
21
6
 
22
- /**
23
- * Safe copies of Error built-ins via factory functions.
24
- *
25
- * Since constructors cannot be safely captured via Object.assign, this module
26
- * provides factory functions that use Reflect.construct internally.
27
- *
28
- * These references are captured at module initialization time to protect against
29
- * prototype pollution attacks. Import only what you need for tree-shaking.
30
- *
31
- * @module @hyperfrontend/immutable-api-utils/built-in-copy/error
32
- */
33
7
  const _Error = globalThis.Error;
34
8
  const _Reflect$1 = globalThis.Reflect;
35
- /**
36
- * (Safe copy) Creates a new Error using the captured Error constructor.
37
- * Use this instead of `new Error()`.
38
- *
39
- * @param message - Optional error message.
40
- * @param options - Optional error options.
41
- * @returns A new Error instance.
42
- *
43
- * @example Creating Error instances
44
- * ```typescript
45
- * const error = createError('Operation failed')
46
- * // With cause for error chaining
47
- * const wrapped = createError('Request failed', { cause: originalError })
48
- * ```
49
- */
50
9
  const createError = (message, options) => _Reflect$1.construct(_Error, [message, options]);
51
10
 
52
- /**
53
- * Safe copies of Object built-in methods.
54
- *
55
- * These references are captured at module initialization time to protect against
56
- * prototype pollution attacks. Import only what you need for tree-shaking.
57
- *
58
- * @module @hyperfrontend/immutable-api-utils/built-in-copy/object
59
- */
60
11
  const _Object = globalThis.Object;
61
- /**
62
- * (Safe copy) Prevents modification of existing property attributes and values,
63
- * and prevents the addition of new properties.
64
- */
65
12
  const freeze = _Object.freeze;
66
13
 
67
- const registeredClasses = [];
68
-
69
- /**
70
- * Returns the data type of the target.
71
- * Uses native `typeof` operator, however, makes distinction between `null`, `array`, and `object`.
72
- * Also, when classes are registered via `registerClass`, it checks if objects are instance of any known registered class.
73
- *
74
- * @param target - The target to get the data type of.
75
- * @returns The data type of the target.
76
- *
77
- * @example Determining data types
78
- * ```typescript
79
- * getType([1, 2]) // 'array'
80
- * getType({ a: 1 }) // 'object'
81
- * getType(null) // 'null'
82
- * ```
83
- */
84
- const getType = (target) => {
85
- if (target === null)
86
- return 'null';
87
- const nativeDataType = typeof target;
88
- if (nativeDataType === 'object') {
89
- if (isArray(target))
90
- return 'array';
91
- for (const registeredClass of registeredClasses) {
92
- if (target instanceof registeredClass)
93
- return registeredClass.name;
94
- }
95
- }
96
- return nativeDataType;
97
- };
98
-
99
- /**
100
- * Safe Set factory for protected set construction.
101
- *
102
- * @module @hyperfrontend/immutable-api-utils/built-in-copy/set
103
- */
104
- /* eslint-disable workspace/lib-require-jsdoc-example */
105
14
  const _Set = globalThis.Set;
106
15
  const _Reflect = globalThis.Reflect;
107
- /**
108
- * (Safe copy) Creates a new Set using the captured Set constructor.
109
- * Use this instead of `new Set()`.
110
- *
111
- * @param iterable - Optional iterable of values.
112
- * @returns A new Set instance.
113
- */
114
16
  const createSet = (iterable) => _Reflect.construct(_Set, iterable ? [iterable] : []);
115
17
 
116
- /**
117
- * Creates a FIFO (First-In-First-Out) list.
118
- *
119
- * @template T The type of elements in the list, must be an object.
120
- * @returns {FifoList<T>} A FIFO list with methods to manipulate and query the list.
121
- * @example Creating and using FIFO queue
122
- * ```typescript
123
- * interface Task { id: number; name: string }
124
- * const queue = createFifoList<Task>()
125
- *
126
- * queue.push({ id: 1, name: 'first' })
127
- * queue.push({ id: 2, name: 'second' })
128
- *
129
- * queue.pull() // => { id: 1, name: 'first' }
130
- * queue.pull() // => { id: 2, name: 'second' }
131
- * ```
132
- */
18
+ const isNonPrimitive$1 = (value) => (typeof value === 'object' && value !== null) || typeof value === 'function';
133
19
  function createFifoList() {
134
20
  const list = createSet();
135
21
  const push = (item) => {
136
- if (getType(item) !== 'object') {
137
- throw createError('A fifo list only non-primitive values');
22
+ if (!isNonPrimitive$1(item)) {
23
+ throw createError('A fifo list only supports non-primitive values');
138
24
  }
139
25
  if (list.has(item)) {
140
- throw createError('Cannot a item that already exists');
26
+ throw createError('Cannot push an item that already exists in the list');
141
27
  }
142
28
  list.add(item);
143
29
  };
@@ -169,27 +55,11 @@ var HyperfrontendListUtils = (function (exports) {
169
55
  return freeze(result);
170
56
  }
171
57
 
172
- /**
173
- * Creates a LIFO (Last-In-First-Out) list.
174
- *
175
- * @template T The type of elements in the list, must be an object.
176
- * @returns {LifoList<T>} A LIFO list with methods to manipulate and query the list.
177
- * @example Creating and using LIFO stack
178
- * ```typescript
179
- * interface HistoryEntry { url: string; timestamp: number }
180
- * const history = createLifoList<HistoryEntry>()
181
- *
182
- * history.push({ url: '/home', timestamp: 1 })
183
- * history.push({ url: '/about', timestamp: 2 })
184
- *
185
- * history.pull() // => { url: '/about', timestamp: 2 }
186
- * history.pull() // => { url: '/home', timestamp: 1 }
187
- * ```
188
- */
58
+ const isNonPrimitive = (value) => (typeof value === 'object' && value !== null) || typeof value === 'function';
189
59
  function createLifoList() {
190
60
  const list = createSet();
191
61
  const push = (item) => {
192
- if (getType(item) !== 'object') {
62
+ if (!isNonPrimitive(item)) {
193
63
  throw createError('A lifo list only supports non-primitive values');
194
64
  }
195
65
  list.add(item);
@@ -226,21 +96,6 @@ var HyperfrontendListUtils = (function (exports) {
226
96
  return freeze(result);
227
97
  }
228
98
 
229
- /**
230
- * Creates an array of numbers within a specified range (inclusive).
231
- *
232
- * @param start - The starting number of the range
233
- * @param end - The ending number of the range (inclusive)
234
- * @returns An array containing all numbers from start to end
235
- * @example Generating number ranges
236
- * ```typescript
237
- * createRange(1, 5)
238
- * // => [1, 2, 3, 4, 5]
239
- *
240
- * createRange(3, 3)
241
- * // => [3]
242
- * ```
243
- */
244
99
  function createRange(start, end) {
245
100
  const range = [];
246
101
  for (let i = start; i <= end; i += 1) {
@@ -249,42 +104,16 @@ var HyperfrontendListUtils = (function (exports) {
249
104
  return range;
250
105
  }
251
106
 
252
- /**
253
- * Creates a value picker that cycles through a list of string values.
254
- *
255
- * @param values - The array of string values to cycle through
256
- * @returns A ValuePicker instance with current and next methods
257
- * @example Cycling through values
258
- * ```typescript
259
- * const colorPicker = createValuePicker(['red', 'green', 'blue'])
260
- *
261
- * colorPicker.current() // => 'red'
262
- * colorPicker.next() // => 'red' (first call initializes)
263
- * colorPicker.next() // => 'green'
264
- * colorPicker.next() // => 'blue'
265
- * colorPicker.next() // => 'red' (cycles back)
266
- * ```
267
- */
268
107
  function createValuePicker(values) {
269
108
  if (!values || !values.length) {
270
109
  throw createError('Expected values not to be an empty list.');
271
110
  }
272
111
  let index = -1;
273
- /**
274
- * Returns the current value without advancing the picker.
275
- *
276
- * @returns The current value in the list
277
- */
278
112
  function current() {
279
113
  if (index < 0)
280
114
  index = 0;
281
115
  return values[index];
282
116
  }
283
- /**
284
- * Advances to and returns the next value, cycling back to the start when reaching the end.
285
- *
286
- * @returns The next value in the list
287
- */
288
117
  function next() {
289
118
  if (index < 0)
290
119
  return current();
@@ -297,53 +126,15 @@ var HyperfrontendListUtils = (function (exports) {
297
126
  };
298
127
  }
299
128
 
300
- /* eslint-disable @typescript-eslint/no-explicit-any */
301
- /**
302
- * Retrieves the final key from a Map by converting keys to an array.
303
- *
304
- * @param map - The Map to extract the last key from
305
- * @returns The key that was inserted last, or undefined if map is empty
306
- * @example Getting last key from Map
307
- * ```typescript
308
- * const userRoles = new Map<string, string>()
309
- * userRoles.set('alice', 'admin')
310
- * userRoles.set('bob', 'editor')
311
- * userRoles.set('charlie', 'viewer')
312
- *
313
- * getLastKeyInMap(userRoles) // => 'charlie'
314
- * ```
315
- */
316
129
  const getLastKeyInMap = (map) => {
317
130
  const items = [...map.keys()];
318
131
  return items[items.length - 1];
319
132
  };
320
133
 
321
- /**
322
- * Filters out empty, null, undefined, and whitespace-only strings from an array.
323
- *
324
- * @param values - The array of strings to filter
325
- * @returns A new array containing only non-empty strings with content
326
- * @example Filtering empty strings
327
- * ```typescript
328
- * nonEmptyStrings(['hello', '', ' ', 'world', null as unknown as string])
329
- * // => ['hello', 'world']
330
- * ```
331
- */
332
134
  function nonEmptyStrings(values) {
333
135
  return values.filter((value) => ![undefined, null, ''].includes(value) && value.trim() !== '');
334
136
  }
335
137
 
336
- /**
337
- * Removes duplicate strings from an array, preserving insertion order.
338
- *
339
- * @param values - The array of strings to deduplicate
340
- * @returns A new array containing only unique strings
341
- * @example Deduplicating strings
342
- * ```typescript
343
- * uniqueStrings(['apple', 'banana', 'apple', 'cherry', 'banana'])
344
- * // => ['apple', 'banana', 'cherry']
345
- * ```
346
- */
347
138
  function uniqueStrings(values) {
348
139
  return from(createSet(values));
349
140
  }
@@ -1 +1 @@
1
- var HyperfrontendListUtils=function(e){"use strict";const t=globalThis.Array,r=t.isArray,n=t.from,o=globalThis.Error,i=globalThis.Reflect,l=(e,t)=>i.construct(o,[e,t]),s=globalThis.Object.freeze,a=[],u=e=>{if(null===e)return"null";const t=typeof e;if("object"===t){if(r(e))return"array";for(const t of a)if(e instanceof t)return t.name}return t},c=globalThis.Set,f=globalThis.Reflect,h=e=>f.construct(c,e?[e]:[]);return e.createFifoList=function(){const e=h();return s({push:t=>{if("object"!==u(t))throw l("A fifo list only non-primitive values");if(e.has(t))throw l("Cannot a item that already exists");e.add(t)},pull:()=>{const t=e.values().next().value;return e.delete(t),t},map:t=>n(e.values()).map(t),forEach:t=>{e.forEach(t)},remove:t=>e.delete(t),has:t=>e.has(t),size:()=>e.size,clear:()=>e.clear()})},e.createLifoList=function(){const e=h();return s({push:t=>{if("object"!==u(t))throw l("A lifo list only supports non-primitive values");e.add(t)},pull:()=>{const t=n(e).pop();return t&&e.delete(t),t},map:t=>n(e).map(t),forEach:t=>{e.forEach(t)},remove:t=>e.delete(t),has:t=>e.has(t),size:()=>e.size,clear:()=>{e.clear()}})},e.createRange=function(e,t){const r=[];for(let n=e;n<=t;n+=1)r.push(n);return r},e.createValuePicker=function(e){if(!e||!e.length)throw l("Expected values not to be an empty list.");let t=-1;function r(){return t<0&&(t=0),e[t]}return{current:r,next:function(){return t<0?r():(t=++t<e.length?t:0,e[t])}}},e.getLastKeyInMap=e=>{const t=[...e.keys()];return t[t.length-1]},e.nonEmptyStrings=function(e){return e.filter(e=>![void 0,null,""].includes(e)&&""!==e.trim())},e.uniqueStrings=function(e){return n(h(e))},e}({});
1
+ var HyperfrontendListUtils=function(t){"use strict";const e=globalThis.Array.from,n=globalThis.Error,r=globalThis.Reflect,o=(t,e)=>r.construct(n,[t,e]),i=globalThis.Object.freeze,l=globalThis.Set,s=globalThis.Reflect,a=t=>s.construct(l,t?[t]:[]);return t.createFifoList=function(){const t=a();return i({push:e=>{if(("object"!=typeof(n=e)||null===n)&&"function"!=typeof n)throw o("A fifo list only supports non-primitive values");var n;if(t.has(e))throw o("Cannot push an item that already exists in the list");t.add(e)},pull:()=>{const e=t.values().next().value;return t.delete(e),e},map:n=>e(t.values()).map(n),forEach:e=>{t.forEach(e)},remove:e=>t.delete(e),has:e=>t.has(e),size:()=>t.size,clear:()=>t.clear()})},t.createLifoList=function(){const t=a();return i({push:e=>{if(("object"!=typeof(n=e)||null===n)&&"function"!=typeof n)throw o("A lifo list only supports non-primitive values");var n;t.add(e)},pull:()=>{const n=e(t).pop();return n&&t.delete(n),n},map:n=>e(t).map(n),forEach:e=>{t.forEach(e)},remove:e=>t.delete(e),has:e=>t.has(e),size:()=>t.size,clear:()=>{t.clear()}})},t.createRange=function(t,e){const n=[];for(let r=t;r<=e;r+=1)n.push(r);return n},t.createValuePicker=function(t){if(!t||!t.length)throw o("Expected values not to be an empty list.");let e=-1;function n(){return e<0&&(e=0),t[e]}return{current:n,next:function(){return e<0?n():(e=++e<t.length?e:0,t[e])}}},t.getLastKeyInMap=t=>{const e=[...t.keys()];return e[e.length-1]},t.nonEmptyStrings=function(t){return t.filter(t=>![void 0,null,""].includes(t)&&""!==t.trim())},t.uniqueStrings=function(t){return e(a(t))},t}({});