@hyperfrontend/list-utils 0.1.0 → 0.1.2
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 +69 -0
- package/README.md +37 -33
- package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/array/{index.cjs.js → index.cjs} +0 -2
- package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/array/{index.esm.js → index.mjs} +1 -2
- package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/object/{index.cjs.js → index.cjs} +0 -2
- package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/object/{index.esm.js → index.mjs} +1 -2
- package/bundle/index.iife.js +4 -20
- package/bundle/index.iife.min.js +1 -1
- package/bundle/index.umd.js +4 -20
- package/bundle/index.umd.min.js +1 -1
- package/{index.cjs.js → index.cjs} +33 -20
- package/{index.esm.js → index.mjs} +21 -8
- package/package.json +8 -6
- package/_dependencies/@hyperfrontend/data-utils/index.cjs.js +0 -214
- package/_dependencies/@hyperfrontend/data-utils/index.esm.js +0 -202
- package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/date/index.cjs.js +0 -8
- package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/date/index.esm.js +0 -7
- package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/map/index.cjs.js +0 -6
- package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/map/index.esm.js +0 -5
- package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/math/index.cjs.js +0 -7
- package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/math/index.esm.js +0 -5
- /package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/error/{index.cjs.js → index.cjs} +0 -0
- /package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/error/{index.esm.js → index.mjs} +0 -0
- /package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/set/{index.cjs.js → index.cjs} +0 -0
- /package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/set/{index.esm.js → index.mjs} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,75 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [0.1.2](https://github.com/AndrewRedican/hyperfrontend/compare/41325ecf9b3f15f597cddadd5fbe6ab68f59eab7...e1fedeaec2e4a890fb7767750298f48de3434cbe) - 2026-11-05
|
|
6
|
+
|
|
7
|
+
### Breaking Changes
|
|
8
|
+
|
|
9
|
+
- **BREAKING** **lib-builder:** stop loading the rollup worker from the bundle/rollup entry
|
|
10
|
+
- **BREAKING** **lib-builder:** emit index.mjs and index.cjs for module outputs
|
|
11
|
+
- **BREAKING** **lib-builder:** fail the build on a declared export it cannot publish
|
|
12
|
+
|
|
13
|
+
### Dependency Updates
|
|
14
|
+
|
|
15
|
+
- **tool-package:** let the version batch inherit the commit window
|
|
16
|
+
- **tool-package:** release a library the graph rebuilds
|
|
17
|
+
- **tool-package:** declare operating systems in make-publishable output
|
|
18
|
+
- **tool-package:** quote the e2e and publish executors' npm spawns for cmd.exe
|
|
19
|
+
- **tool-package:** run the nx e2e suites one at a time on windows
|
|
20
|
+
- **lib-builder:** keep platform-restricted packages external
|
|
21
|
+
- **lib-builder:** keep chunks a bare side-effect import reaches
|
|
22
|
+
- **lib-builder:** fail the build on a declaration alias cycle between entries
|
|
23
|
+
- **lib-builder:** list every third-party package the output inlines in THIRD_PARTY_LICENSES.md
|
|
24
|
+
- **lib-builder:** reproduce dependency license texts in THIRD_PARTY_LICENSES.md
|
|
25
|
+
- **tool-package:** drop npm's silent flag from the version remedies
|
|
26
|
+
- **tool-package:** locate generator templates from the tree root
|
|
27
|
+
- **tool-package:** add a provenance option to the publish executor
|
|
28
|
+
- **tool-package:** locate the test runner from the workspace root
|
|
29
|
+
- **tool-package:** scaffold e2e specs on the packed consumer
|
|
30
|
+
- **tool-package:** hand e2e suites the packed tarball path
|
|
31
|
+
- **lib-builder:** skip type checking in workers that drop diagnostics
|
|
32
|
+
- **lib-builder:** build browser bundles from one entry, refuse several
|
|
33
|
+
- **lib-builder:** inline dynamic imports into each library entry bundle
|
|
34
|
+
- **tool-package:** drop the e2e template's unknown rule directive
|
|
35
|
+
- **tool-package:** keep existing config when make-publishable re-runs
|
|
36
|
+
- **tool-package:** import make-publishable statically
|
|
37
|
+
- **tool-package:** scaffold libraries with the workspace lint config
|
|
38
|
+
- **lib-builder:** strip lint pragmas from bundled dependency code
|
|
39
|
+
- **tool-package:** typecheck each project's spec config alongside its library config
|
|
40
|
+
- **tool-package:** scaffold e2e projects with an audit target and assertive spec names
|
|
41
|
+
- **tool-package:** scaffold libraries at 0.0.0 with a bare test target and runner config types
|
|
42
|
+
- **tool-package:** register a publishable library in ci, the root readme and the docs site
|
|
43
|
+
- **lib-builder:** build the bin descriptor's output dir natively
|
|
44
|
+
- **lib-builder:** keep resolved workspace dependency paths native
|
|
45
|
+
- **tool-package:** quote the tarball path when npm runs through the windows shell
|
|
46
|
+
- **lib-builder:** drop type diagnostics computed without path mappings
|
|
47
|
+
- **lib-builder:** retry report directory removal on transient windows locks
|
|
48
|
+
- **lib-builder:** keep core modules external without module.isBuiltin
|
|
49
|
+
- **BREAKING** **lib-builder:** stop loading the rollup worker from the bundle/rollup entry
|
|
50
|
+
- **lib-builder:** expose the crypto global to the rollup worker on node 18
|
|
51
|
+
- **BREAKING** **lib-builder:** emit index.mjs and index.cjs for module outputs
|
|
52
|
+
- **tool-package:** run the tsc entry script on node for typecheck
|
|
53
|
+
- **lib-builder:** run the tsc entry script on node for declaration emit
|
|
54
|
+
- **tool-package:** pass the e2e executor preloads as file urls
|
|
55
|
+
- **tool-package:** pass the test executor preload as a file url
|
|
56
|
+
- **tool-package:** report workspace-relative paths with posix separators
|
|
57
|
+
- **tool-package:** split text on crlf line endings
|
|
58
|
+
- **tool-package:** spawn npm through a shell on windows
|
|
59
|
+
- **lib-builder:** split worker stderr on crlf line endings
|
|
60
|
+
- **lib-builder:** rewrite only native separators to forward slashes
|
|
61
|
+
- **lib-builder:** walk up to package.json from native windows paths
|
|
62
|
+
- **lib-builder:** guard bundled deps against native windows paths
|
|
63
|
+
- **BREAKING** **lib-builder:** fail the build on a declared export it cannot publish
|
|
64
|
+
- **tool-package:** fold the compatibility matrix into the version commit
|
|
65
|
+
- **tool-package:** expose the builder clean option to projects
|
|
66
|
+
- **lib-builder:** clean only an owned output and add the clean option
|
|
67
|
+
|
|
68
|
+
## [0.1.1](https://github.com/AndrewRedican/hyperfrontend/compare/29dc54d58c2b3c8b8dd35f7c546ebc6cd9191f6e...adf0a4f77dece2be855e7ab88185a4fe84e7b16b) - 2026-09-14
|
|
69
|
+
|
|
70
|
+
### Bug Fixes
|
|
71
|
+
|
|
72
|
+
- accept arrays, functions and class instances in fifo and lifo lists
|
|
73
|
+
|
|
5
74
|
## [0.1.0](https://github.com/AndrewRedican/hyperfrontend/compare/5f116abb8ba6355dfb283fa03b7481e5eb029480...cc16961a470190848f71a7cce41f7377bc4511a4) - 2026-08-25
|
|
6
75
|
|
|
7
76
|
### Breaking Changes
|
package/README.md
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
|
|
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,6 +37,12 @@
|
|
|
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/)
|
|
@@ -46,16 +56,16 @@ The library enforces immutability through frozen interfaces while maintaining hi
|
|
|
46
56
|
|
|
47
57
|
### Key Features
|
|
48
58
|
|
|
49
|
-
- **FIFO and LIFO queues** with type-safe object tracking
|
|
50
|
-
- **Value picker** for cyclical iteration (ideal for round-robin patterns)
|
|
51
|
-
- **String sanitization** utilities (dedupe, trim, filter empty)
|
|
52
|
-
- **Range generation** for loop-free number sequences
|
|
53
|
-
- **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
|
|
54
64
|
- **Zero dependencies** - Self-contained implementation with no third-party runtime dependencies
|
|
55
65
|
|
|
56
66
|
### Architecture Highlights
|
|
57
67
|
|
|
58
|
-
|
|
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.
|
|
59
69
|
|
|
60
70
|
## Why Use @hyperfrontend/list-utils?
|
|
61
71
|
|
|
@@ -99,47 +109,41 @@ colorPicker.next() // 'blue'
|
|
|
99
109
|
colorPicker.next() // 'green'
|
|
100
110
|
colorPicker.next() // 'red' (cycles back)
|
|
101
111
|
|
|
102
|
-
// String sanitization
|
|
112
|
+
// String sanitization: blanks are dropped, survivors keep their original padding
|
|
103
113
|
const userInputs = [' hello ', '', 'world', null, 'hello', ' ', 'world']
|
|
104
|
-
const cleaned = uniqueStrings(nonEmptyStrings(userInputs)) // ['hello', 'world']
|
|
114
|
+
const cleaned = uniqueStrings(nonEmptyStrings(userInputs)) // [' hello ', 'world', 'hello']
|
|
105
115
|
```
|
|
106
116
|
|
|
107
117
|
## API Overview
|
|
108
118
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
- **`createFifoList<T>()`** - First-in-first-out queue with reference uniqueness
|
|
112
|
-
- **`createLifoList<T>()`** - Last-in-first-out stack with reference uniqueness
|
|
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.
|
|
113
120
|
|
|
114
|
-
|
|
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.
|
|
115
122
|
|
|
116
|
-
|
|
117
|
-
- **`createRange(start, end)`** - Generate number arrays without loops
|
|
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`.
|
|
118
124
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
- **`nonEmptyStrings(values)`** - Filter null/undefined/empty/whitespace strings
|
|
122
|
-
- **`uniqueStrings(values)`** - Remove duplicates while preserving order
|
|
123
|
-
|
|
124
|
-
### Map Helpers
|
|
125
|
-
|
|
126
|
-
- **`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).
|
|
127
126
|
|
|
128
127
|
## Compatibility
|
|
129
128
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
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>
|
|
134
|
+
|
|
135
|
+
| Operating System | Supported |
|
|
136
|
+
| ---------------- | :-------: |
|
|
137
|
+
| Linux | ✅ |
|
|
138
|
+
| macOS | ✅ |
|
|
139
|
+
| Windows | ✅ |
|
|
136
140
|
|
|
137
141
|
### Output Formats
|
|
138
142
|
|
|
139
143
|
| Format | File | Tree-Shakeable |
|
|
140
144
|
| ------ | -------------------------- | :------------: |
|
|
141
|
-
| ESM | `index.
|
|
142
|
-
| CJS | `index.cjs
|
|
145
|
+
| ESM | `index.mjs` | ✅ |
|
|
146
|
+
| CJS | `index.cjs` | ❌ |
|
|
143
147
|
| IIFE | `bundle/index.iife.min.js` | ❌ |
|
|
144
148
|
| UMD | `bundle/index.umd.min.js` | ❌ |
|
|
145
149
|
|
|
@@ -157,7 +161,7 @@ const cleaned = uniqueStrings(nonEmptyStrings(userInputs)) // ['hello', 'world']
|
|
|
157
161
|
</script>
|
|
158
162
|
```
|
|
159
163
|
|
|
160
|
-
**Global variable:** `HyperfrontendListUtils`
|
|
164
|
+
**Global variable:** [`HyperfrontendListUtils`](https://www.hyperfrontend.dev/docs/libraries/utils/list/)
|
|
161
165
|
|
|
162
166
|
## Part of hyperfrontend
|
|
163
167
|
|
package/bundle/index.iife.js
CHANGED
|
@@ -2,7 +2,6 @@ var HyperfrontendListUtils = (function (exports) {
|
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
const _Array = globalThis.Array;
|
|
5
|
-
const isArray = _Array.isArray;
|
|
6
5
|
const from = _Array.from;
|
|
7
6
|
|
|
8
7
|
const _Error = globalThis.Error;
|
|
@@ -12,31 +11,15 @@ var HyperfrontendListUtils = (function (exports) {
|
|
|
12
11
|
const _Object = globalThis.Object;
|
|
13
12
|
const freeze = _Object.freeze;
|
|
14
13
|
|
|
15
|
-
const registeredClasses = [];
|
|
16
|
-
|
|
17
|
-
const getType = (target) => {
|
|
18
|
-
if (target === null)
|
|
19
|
-
return 'null';
|
|
20
|
-
const nativeDataType = typeof target;
|
|
21
|
-
if (nativeDataType === 'object') {
|
|
22
|
-
if (isArray(target))
|
|
23
|
-
return 'array';
|
|
24
|
-
for (const registeredClass of registeredClasses) {
|
|
25
|
-
if (target instanceof registeredClass)
|
|
26
|
-
return registeredClass.name;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
return nativeDataType;
|
|
30
|
-
};
|
|
31
|
-
|
|
32
14
|
const _Set = globalThis.Set;
|
|
33
15
|
const _Reflect = globalThis.Reflect;
|
|
34
16
|
const createSet = (iterable) => _Reflect.construct(_Set, iterable ? [iterable] : []);
|
|
35
17
|
|
|
18
|
+
const isNonPrimitive$1 = (value) => (typeof value === 'object' && value !== null) || typeof value === 'function';
|
|
36
19
|
function createFifoList() {
|
|
37
20
|
const list = createSet();
|
|
38
21
|
const push = (item) => {
|
|
39
|
-
if (
|
|
22
|
+
if (!isNonPrimitive$1(item)) {
|
|
40
23
|
throw createError('A fifo list only supports non-primitive values');
|
|
41
24
|
}
|
|
42
25
|
if (list.has(item)) {
|
|
@@ -72,10 +55,11 @@ var HyperfrontendListUtils = (function (exports) {
|
|
|
72
55
|
return freeze(result);
|
|
73
56
|
}
|
|
74
57
|
|
|
58
|
+
const isNonPrimitive = (value) => (typeof value === 'object' && value !== null) || typeof value === 'function';
|
|
75
59
|
function createLifoList() {
|
|
76
60
|
const list = createSet();
|
|
77
61
|
const push = (item) => {
|
|
78
|
-
if (
|
|
62
|
+
if (!isNonPrimitive(item)) {
|
|
79
63
|
throw createError('A lifo list only supports non-primitive values');
|
|
80
64
|
}
|
|
81
65
|
list.add(item);
|
package/bundle/index.iife.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var HyperfrontendListUtils=function(
|
|
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}({});
|
package/bundle/index.umd.js
CHANGED
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
})(this, (function (exports) { 'use strict';
|
|
6
6
|
|
|
7
7
|
const _Array = globalThis.Array;
|
|
8
|
-
const isArray = _Array.isArray;
|
|
9
8
|
const from = _Array.from;
|
|
10
9
|
|
|
11
10
|
const _Error = globalThis.Error;
|
|
@@ -15,31 +14,15 @@
|
|
|
15
14
|
const _Object = globalThis.Object;
|
|
16
15
|
const freeze = _Object.freeze;
|
|
17
16
|
|
|
18
|
-
const registeredClasses = [];
|
|
19
|
-
|
|
20
|
-
const getType = (target) => {
|
|
21
|
-
if (target === null)
|
|
22
|
-
return 'null';
|
|
23
|
-
const nativeDataType = typeof target;
|
|
24
|
-
if (nativeDataType === 'object') {
|
|
25
|
-
if (isArray(target))
|
|
26
|
-
return 'array';
|
|
27
|
-
for (const registeredClass of registeredClasses) {
|
|
28
|
-
if (target instanceof registeredClass)
|
|
29
|
-
return registeredClass.name;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
return nativeDataType;
|
|
33
|
-
};
|
|
34
|
-
|
|
35
17
|
const _Set = globalThis.Set;
|
|
36
18
|
const _Reflect = globalThis.Reflect;
|
|
37
19
|
const createSet = (iterable) => _Reflect.construct(_Set, iterable ? [iterable] : []);
|
|
38
20
|
|
|
21
|
+
const isNonPrimitive$1 = (value) => (typeof value === 'object' && value !== null) || typeof value === 'function';
|
|
39
22
|
function createFifoList() {
|
|
40
23
|
const list = createSet();
|
|
41
24
|
const push = (item) => {
|
|
42
|
-
if (
|
|
25
|
+
if (!isNonPrimitive$1(item)) {
|
|
43
26
|
throw createError('A fifo list only supports non-primitive values');
|
|
44
27
|
}
|
|
45
28
|
if (list.has(item)) {
|
|
@@ -75,10 +58,11 @@
|
|
|
75
58
|
return freeze(result);
|
|
76
59
|
}
|
|
77
60
|
|
|
61
|
+
const isNonPrimitive = (value) => (typeof value === 'object' && value !== null) || typeof value === 'function';
|
|
78
62
|
function createLifoList() {
|
|
79
63
|
const list = createSet();
|
|
80
64
|
const push = (item) => {
|
|
81
|
-
if (
|
|
65
|
+
if (!isNonPrimitive(item)) {
|
|
82
66
|
throw createError('A lifo list only supports non-primitive values');
|
|
83
67
|
}
|
|
84
68
|
list.add(item);
|
package/bundle/index.umd.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).HyperfrontendListUtils={})}(this,function(e){"use strict";const t=globalThis.Array
|
|
1
|
+
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).HyperfrontendListUtils={})}(this,function(e){"use strict";const t=globalThis.Array.from,n=globalThis.Error,o=globalThis.Reflect,r=(e,t)=>o.construct(n,[e,t]),i=globalThis.Object.freeze,l=globalThis.Set,s=globalThis.Reflect,u=e=>s.construct(l,e?[e]:[]);e.createFifoList=function(){const e=u();return i({push:t=>{if(("object"!=typeof(n=t)||null===n)&&"function"!=typeof n)throw r("A fifo list only supports non-primitive values");var n;if(e.has(t))throw r("Cannot push an item that already exists in the list");e.add(t)},pull:()=>{const t=e.values().next().value;return e.delete(t),t},map:n=>t(e.values()).map(n),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=u();return i({push:t=>{if(("object"!=typeof(n=t)||null===n)&&"function"!=typeof n)throw r("A lifo list only supports non-primitive values");var n;e.add(t)},pull:()=>{const n=t(e).pop();return n&&e.delete(n),n},map:n=>t(e).map(n),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 n=[];for(let o=e;o<=t;o+=1)n.push(o);return n},e.createValuePicker=function(e){if(!e||!e.length)throw r("Expected values not to be an empty list.");let t=-1;function n(){return t<0&&(t=0),e[t]}return{current:n,next:function(){return t<0?n():(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 t(u(e))}});
|
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
const index_cjs_js = require('./_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/set/index.cjs.js');
|
|
3
|
+
const index_cjs$3 = require('./_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/array/index.cjs');
|
|
4
|
+
const index_cjs$2 = require('./_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/error/index.cjs');
|
|
5
|
+
const index_cjs$1 = require('./_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/object/index.cjs');
|
|
6
|
+
const index_cjs = require('./_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/set/index.cjs');
|
|
8
7
|
|
|
8
|
+
/**
|
|
9
|
+
* Reports whether a value is a non-primitive, the only kind of value these lists accept.
|
|
10
|
+
*
|
|
11
|
+
* @param value - The value a caller tried to push.
|
|
12
|
+
* @returns True when the value is a non-null object or a function.
|
|
13
|
+
*/
|
|
14
|
+
const isNonPrimitive$1 = (value) => (typeof value === 'object' && value !== null) || typeof value === 'function';
|
|
9
15
|
/**
|
|
10
16
|
* Creates a FIFO (First-In-First-Out) list.
|
|
11
17
|
*
|
|
@@ -27,13 +33,13 @@ const index_cjs_js = require('./_dependencies/@hyperfrontend/immutable-api-utils
|
|
|
27
33
|
* @throws {Error} When the pushed item is already in the list. Use has() to check first if a duplicate is expected.
|
|
28
34
|
*/
|
|
29
35
|
function createFifoList() {
|
|
30
|
-
const list =
|
|
36
|
+
const list = index_cjs.createSet();
|
|
31
37
|
const push = (item) => {
|
|
32
|
-
if (
|
|
33
|
-
throw
|
|
38
|
+
if (!isNonPrimitive$1(item)) {
|
|
39
|
+
throw index_cjs$2.createError('A fifo list only supports non-primitive values');
|
|
34
40
|
}
|
|
35
41
|
if (list.has(item)) {
|
|
36
|
-
throw
|
|
42
|
+
throw index_cjs$2.createError('Cannot push an item that already exists in the list');
|
|
37
43
|
}
|
|
38
44
|
list.add(item);
|
|
39
45
|
};
|
|
@@ -43,7 +49,7 @@ function createFifoList() {
|
|
|
43
49
|
return value;
|
|
44
50
|
};
|
|
45
51
|
const map = (callback) => {
|
|
46
|
-
return
|
|
52
|
+
return index_cjs$3.from(list.values()).map(callback);
|
|
47
53
|
};
|
|
48
54
|
const forEach = (callback) => {
|
|
49
55
|
list.forEach(callback);
|
|
@@ -62,9 +68,16 @@ function createFifoList() {
|
|
|
62
68
|
size,
|
|
63
69
|
clear,
|
|
64
70
|
};
|
|
65
|
-
return
|
|
71
|
+
return index_cjs$1.freeze(result);
|
|
66
72
|
}
|
|
67
73
|
|
|
74
|
+
/**
|
|
75
|
+
* Reports whether a value is a non-primitive, the only kind of value these lists accept.
|
|
76
|
+
*
|
|
77
|
+
* @param value - The value a caller tried to push.
|
|
78
|
+
* @returns True when the value is a non-null object or a function.
|
|
79
|
+
*/
|
|
80
|
+
const isNonPrimitive = (value) => (typeof value === 'object' && value !== null) || typeof value === 'function';
|
|
68
81
|
/**
|
|
69
82
|
* Creates a LIFO (Last-In-First-Out) list.
|
|
70
83
|
*
|
|
@@ -83,22 +96,22 @@ function createFifoList() {
|
|
|
83
96
|
* ```
|
|
84
97
|
*/
|
|
85
98
|
function createLifoList() {
|
|
86
|
-
const list =
|
|
99
|
+
const list = index_cjs.createSet();
|
|
87
100
|
const push = (item) => {
|
|
88
|
-
if (
|
|
89
|
-
throw
|
|
101
|
+
if (!isNonPrimitive(item)) {
|
|
102
|
+
throw index_cjs$2.createError('A lifo list only supports non-primitive values');
|
|
90
103
|
}
|
|
91
104
|
list.add(item);
|
|
92
105
|
};
|
|
93
106
|
const pull = () => {
|
|
94
|
-
const lastItem =
|
|
107
|
+
const lastItem = index_cjs$3.from(list).pop();
|
|
95
108
|
if (lastItem) {
|
|
96
109
|
list.delete(lastItem);
|
|
97
110
|
}
|
|
98
111
|
return lastItem;
|
|
99
112
|
};
|
|
100
113
|
const map = (callback) => {
|
|
101
|
-
return
|
|
114
|
+
return index_cjs$3.from(list).map(callback);
|
|
102
115
|
};
|
|
103
116
|
const forEach = (callback) => {
|
|
104
117
|
list.forEach(callback);
|
|
@@ -119,7 +132,7 @@ function createLifoList() {
|
|
|
119
132
|
size,
|
|
120
133
|
clear,
|
|
121
134
|
};
|
|
122
|
-
return
|
|
135
|
+
return index_cjs$1.freeze(result);
|
|
123
136
|
}
|
|
124
137
|
|
|
125
138
|
/**
|
|
@@ -163,7 +176,7 @@ function createRange(start, end) {
|
|
|
163
176
|
*/
|
|
164
177
|
function createValuePicker(values) {
|
|
165
178
|
if (!values || !values.length) {
|
|
166
|
-
throw
|
|
179
|
+
throw index_cjs$2.createError('Expected values not to be an empty list.');
|
|
167
180
|
}
|
|
168
181
|
let index = -1;
|
|
169
182
|
/**
|
|
@@ -193,7 +206,7 @@ function createValuePicker(values) {
|
|
|
193
206
|
};
|
|
194
207
|
}
|
|
195
208
|
|
|
196
|
-
/*
|
|
209
|
+
/* lint-disable typescript/no-explicit-any */
|
|
197
210
|
/**
|
|
198
211
|
* Retrieves the final key from a Map by converting keys to an array.
|
|
199
212
|
*
|
|
@@ -241,7 +254,7 @@ function nonEmptyStrings(values) {
|
|
|
241
254
|
* ```
|
|
242
255
|
*/
|
|
243
256
|
function uniqueStrings(values) {
|
|
244
|
-
return
|
|
257
|
+
return index_cjs$3.from(index_cjs.createSet(values));
|
|
245
258
|
}
|
|
246
259
|
|
|
247
260
|
exports.createFifoList = createFifoList;
|
|
@@ -1,9 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { createSet } from './_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/set/index.esm.js';
|
|
1
|
+
import { from } from './_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/array/index.mjs';
|
|
2
|
+
import { createError } from './_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/error/index.mjs';
|
|
3
|
+
import { freeze } from './_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/object/index.mjs';
|
|
4
|
+
import { createSet } from './_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/set/index.mjs';
|
|
6
5
|
|
|
6
|
+
/**
|
|
7
|
+
* Reports whether a value is a non-primitive, the only kind of value these lists accept.
|
|
8
|
+
*
|
|
9
|
+
* @param value - The value a caller tried to push.
|
|
10
|
+
* @returns True when the value is a non-null object or a function.
|
|
11
|
+
*/
|
|
12
|
+
const isNonPrimitive$1 = (value) => (typeof value === 'object' && value !== null) || typeof value === 'function';
|
|
7
13
|
/**
|
|
8
14
|
* Creates a FIFO (First-In-First-Out) list.
|
|
9
15
|
*
|
|
@@ -27,7 +33,7 @@ import { createSet } from './_dependencies/@hyperfrontend/immutable-api-utils/bu
|
|
|
27
33
|
function createFifoList() {
|
|
28
34
|
const list = createSet();
|
|
29
35
|
const push = (item) => {
|
|
30
|
-
if (
|
|
36
|
+
if (!isNonPrimitive$1(item)) {
|
|
31
37
|
throw createError('A fifo list only supports non-primitive values');
|
|
32
38
|
}
|
|
33
39
|
if (list.has(item)) {
|
|
@@ -63,6 +69,13 @@ function createFifoList() {
|
|
|
63
69
|
return freeze(result);
|
|
64
70
|
}
|
|
65
71
|
|
|
72
|
+
/**
|
|
73
|
+
* Reports whether a value is a non-primitive, the only kind of value these lists accept.
|
|
74
|
+
*
|
|
75
|
+
* @param value - The value a caller tried to push.
|
|
76
|
+
* @returns True when the value is a non-null object or a function.
|
|
77
|
+
*/
|
|
78
|
+
const isNonPrimitive = (value) => (typeof value === 'object' && value !== null) || typeof value === 'function';
|
|
66
79
|
/**
|
|
67
80
|
* Creates a LIFO (Last-In-First-Out) list.
|
|
68
81
|
*
|
|
@@ -83,7 +96,7 @@ function createFifoList() {
|
|
|
83
96
|
function createLifoList() {
|
|
84
97
|
const list = createSet();
|
|
85
98
|
const push = (item) => {
|
|
86
|
-
if (
|
|
99
|
+
if (!isNonPrimitive(item)) {
|
|
87
100
|
throw createError('A lifo list only supports non-primitive values');
|
|
88
101
|
}
|
|
89
102
|
list.add(item);
|
|
@@ -191,7 +204,7 @@ function createValuePicker(values) {
|
|
|
191
204
|
};
|
|
192
205
|
}
|
|
193
206
|
|
|
194
|
-
/*
|
|
207
|
+
/* lint-disable typescript/no-explicit-any */
|
|
195
208
|
/**
|
|
196
209
|
* Retrieves the final key from a Map by converting keys to an array.
|
|
197
210
|
*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyperfrontend/list-utils",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Purpose-built collection utilities for queue management, filtering, and iteration patterns.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
"./package.json": "./package.json",
|
|
30
30
|
".": {
|
|
31
31
|
"types": "./index.d.ts",
|
|
32
|
-
"import": "./index.
|
|
33
|
-
"require": "./index.cjs
|
|
32
|
+
"import": "./index.mjs",
|
|
33
|
+
"require": "./index.cjs"
|
|
34
34
|
}
|
|
35
35
|
},
|
|
36
36
|
"repository": {
|
|
@@ -45,8 +45,8 @@
|
|
|
45
45
|
"name": "andrew.redican.mejia@gmail.com",
|
|
46
46
|
"url": "https://hyperfrontend.dev"
|
|
47
47
|
},
|
|
48
|
-
"main": "./index.cjs
|
|
49
|
-
"module": "./index.
|
|
48
|
+
"main": "./index.cjs",
|
|
49
|
+
"module": "./index.mjs",
|
|
50
50
|
"types": "./index.d.ts",
|
|
51
51
|
"unpkg": "./bundle/index.umd.min.js",
|
|
52
52
|
"jsdelivr": "./bundle/index.umd.min.js",
|
|
@@ -57,6 +57,8 @@
|
|
|
57
57
|
"LICENSE.md",
|
|
58
58
|
"README.md",
|
|
59
59
|
"SECURITY.md",
|
|
60
|
-
"!**/*.js.map"
|
|
60
|
+
"!**/*.js.map",
|
|
61
|
+
"!**/*.mjs.map",
|
|
62
|
+
"!**/*.cjs.map"
|
|
61
63
|
]
|
|
62
64
|
}
|
|
@@ -1,214 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const { isArray } = require('../immutable-api-utils/built-in-copy/array/index.cjs.js');
|
|
4
|
-
const { createError } = require('../immutable-api-utils/built-in-copy/error/index.cjs.js');
|
|
5
|
-
const { freeze, keys: keys$1 } = require('../immutable-api-utils/built-in-copy/object/index.cjs.js');
|
|
6
|
-
const { createMap } = require('../immutable-api-utils/built-in-copy/map/index.cjs.js');
|
|
7
|
-
const { createDate } = require('../immutable-api-utils/built-in-copy/date/index.cjs.js');
|
|
8
|
-
const { random, round } = require('../immutable-api-utils/built-in-copy/math/index.cjs.js');
|
|
9
|
-
|
|
10
|
-
const isMarker = (text) => {
|
|
11
|
-
if (typeof text !== 'string' || !text.startsWith('__$'))
|
|
12
|
-
return false;
|
|
13
|
-
return /^__\$[0-9]+$/.test(text);
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
const registeredClasses = [];
|
|
17
|
-
const registeredIterableClasses = [
|
|
18
|
-
{
|
|
19
|
-
classRef: Array,
|
|
20
|
-
instantiate: () => [],
|
|
21
|
-
getKeys: (target) => {
|
|
22
|
-
const keysArray = keys$1(target);
|
|
23
|
-
if (getConfig().detectCircularReferences) {
|
|
24
|
-
return keysArray.filter((key) => !isMarker(key));
|
|
25
|
-
}
|
|
26
|
-
return keysArray;
|
|
27
|
-
},
|
|
28
|
-
read: (target, key) => target[key],
|
|
29
|
-
write: (target, value, key) => (target[key] = value),
|
|
30
|
-
remove: (target, value) => target.splice(value, 1),
|
|
31
|
-
},
|
|
32
|
-
{
|
|
33
|
-
classRef: Object,
|
|
34
|
-
instantiate: () => ({}),
|
|
35
|
-
getKeys: (target) => {
|
|
36
|
-
const keysArray = keys$1(target);
|
|
37
|
-
if (getConfig().detectCircularReferences) {
|
|
38
|
-
return keysArray.filter((key) => !isMarker(key));
|
|
39
|
-
}
|
|
40
|
-
return keysArray;
|
|
41
|
-
},
|
|
42
|
-
read: (target, key) => target[key],
|
|
43
|
-
write: (target, value, key) => (target[key] = value),
|
|
44
|
-
remove: (target, value) => delete target[value],
|
|
45
|
-
},
|
|
46
|
-
];
|
|
47
|
-
let samePositionOfOwnProperties = false;
|
|
48
|
-
let detectCircularReferences = false;
|
|
49
|
-
const getConfig = () => ({
|
|
50
|
-
samePositionOfOwnProperties,
|
|
51
|
-
detectCircularReferences,
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
const getKeysFromIterable = (target, dataType) => {
|
|
55
|
-
if (dataType === 'array')
|
|
56
|
-
dataType = Array.name;
|
|
57
|
-
if (dataType === 'object')
|
|
58
|
-
dataType = Object.name;
|
|
59
|
-
const iterableClass = registeredIterableClasses.find(({ classRef }) => dataType === classRef.name);
|
|
60
|
-
if (iterableClass === undefined)
|
|
61
|
-
return [];
|
|
62
|
-
return iterableClass.getKeys(target);
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
const getType = (target) => {
|
|
66
|
-
if (target === null)
|
|
67
|
-
return 'null';
|
|
68
|
-
const nativeDataType = typeof target;
|
|
69
|
-
if (nativeDataType === 'object') {
|
|
70
|
-
if (isArray(target))
|
|
71
|
-
return 'array';
|
|
72
|
-
for (const registeredClass of registeredClasses) {
|
|
73
|
-
if (target instanceof registeredClass)
|
|
74
|
-
return registeredClass.name;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
return nativeDataType;
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
const getIterableTypes = () => registeredIterableClasses.map(({ classRef }) => {
|
|
81
|
-
const name = classRef.name;
|
|
82
|
-
if (name === Object.name)
|
|
83
|
-
return 'object';
|
|
84
|
-
if (name === Array.name)
|
|
85
|
-
return 'array';
|
|
86
|
-
return name;
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
const isIterableType = (dataType) => getIterableTypes().includes(dataType);
|
|
90
|
-
|
|
91
|
-
const isIterable = (target) => isIterableType(getType(target));
|
|
92
|
-
|
|
93
|
-
const marker = () => {
|
|
94
|
-
const randomValue = round(random() * 10000000000000);
|
|
95
|
-
const sequential = createDate().getTime();
|
|
96
|
-
const unique = `${randomValue}${sequential}`;
|
|
97
|
-
const prefix = `__$`;
|
|
98
|
-
return `${prefix}${unique}`;
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
const referenceStack = () => {
|
|
102
|
-
const records = createMap();
|
|
103
|
-
const flag = marker();
|
|
104
|
-
const exists = (ref) => (isIterable(ref) ? flag in ref && records.has(ref[flag]) : false);
|
|
105
|
-
const add = (ref) => {
|
|
106
|
-
if (!isIterable(ref) || exists(ref))
|
|
107
|
-
return;
|
|
108
|
-
ref[flag] = Symbol();
|
|
109
|
-
records.set(ref[flag], [flag, ref, records.size]);
|
|
110
|
-
};
|
|
111
|
-
const lastSeen = (ref) => {
|
|
112
|
-
if (!isIterable(ref))
|
|
113
|
-
return null;
|
|
114
|
-
const record = records.get(ref[flag]);
|
|
115
|
-
return record ? record[2] - records.size : null;
|
|
116
|
-
};
|
|
117
|
-
const clear = () => (records.forEach(([key, ref]) => {
|
|
118
|
-
delete ref[key];
|
|
119
|
-
}),
|
|
120
|
-
records.clear());
|
|
121
|
-
return {
|
|
122
|
-
add: (ref) => add(ref),
|
|
123
|
-
exists: (ref) => exists(ref),
|
|
124
|
-
lastSeen: (ref) => lastSeen(ref),
|
|
125
|
-
clear: () => clear(),
|
|
126
|
-
get size() {
|
|
127
|
-
return records.size;
|
|
128
|
-
},
|
|
129
|
-
};
|
|
130
|
-
};
|
|
131
|
-
|
|
132
|
-
const errorMessage = (thing, type) => `Expected ${thing} to be ${type}.`;
|
|
133
|
-
const nextIterationDetails = (path, key, value) => ({
|
|
134
|
-
nextPath: [...path, key],
|
|
135
|
-
nextValue: value[key],
|
|
136
|
-
});
|
|
137
|
-
const circularDependencyTraversal = (condition, callback, config, key, path, value, parent, state, stack, root = false) => {
|
|
138
|
-
if (stack.exists(value))
|
|
139
|
-
return state;
|
|
140
|
-
const ok = condition(config, key, value, path, parent);
|
|
141
|
-
if (config.exitEarly)
|
|
142
|
-
return state;
|
|
143
|
-
if (ok)
|
|
144
|
-
callback(key, value, path, state, parent);
|
|
145
|
-
stack.add(value);
|
|
146
|
-
const type = getType(value);
|
|
147
|
-
if (!isIterableType(type))
|
|
148
|
-
return state;
|
|
149
|
-
const keys = getKeysFromIterable(value, type);
|
|
150
|
-
keys.forEach((key) => {
|
|
151
|
-
const { nextPath, nextValue } = nextIterationDetails(path, key, value);
|
|
152
|
-
circularDependencyTraversal(condition, callback, config, key, nextPath, nextValue, value, state, stack);
|
|
153
|
-
});
|
|
154
|
-
if (root)
|
|
155
|
-
stack.clear();
|
|
156
|
-
return state;
|
|
157
|
-
};
|
|
158
|
-
const nonCircularDependencyTraversal = (condition, callback, config, key, path, value, parent, state) => {
|
|
159
|
-
const ok = condition(config, key, value, path, parent);
|
|
160
|
-
if (config.exitEarly)
|
|
161
|
-
return state;
|
|
162
|
-
if (ok)
|
|
163
|
-
callback(key, value, path, state, parent);
|
|
164
|
-
const type = getType(value);
|
|
165
|
-
if (!isIterableType(type))
|
|
166
|
-
return state;
|
|
167
|
-
const keys = getKeysFromIterable(value, type);
|
|
168
|
-
keys.forEach((key) => {
|
|
169
|
-
const { nextPath, nextValue } = nextIterationDetails(path, key, value);
|
|
170
|
-
nonCircularDependencyTraversal(condition, callback, config, key, nextPath, nextValue, value, state);
|
|
171
|
-
});
|
|
172
|
-
return state;
|
|
173
|
-
};
|
|
174
|
-
const traversal = (target, condition, callback, options, state) => {
|
|
175
|
-
if (typeof callback !== 'function')
|
|
176
|
-
throw createError(errorMessage('callback', 'a function'));
|
|
177
|
-
if (!(typeof options === 'object' && !isArray(options)))
|
|
178
|
-
throw createError(errorMessage('options', 'an object'));
|
|
179
|
-
if (!isArray(options.depth))
|
|
180
|
-
throw createError(errorMessage('options.depth', 'an array'));
|
|
181
|
-
const [startDepth, maxDepth] = options.depth;
|
|
182
|
-
if (startDepth !== void 0 && typeof startDepth !== 'number')
|
|
183
|
-
throw createError(errorMessage('options.depth.0', 'a number'));
|
|
184
|
-
if (maxDepth !== void 0) {
|
|
185
|
-
const maxDepthType = typeof maxDepth;
|
|
186
|
-
if (!['number', 'string'].includes(maxDepthType))
|
|
187
|
-
throw createError(errorMessage('options.depth.1', 'a number or a string'));
|
|
188
|
-
if (maxDepthType === 'string' && maxDepth !== '*')
|
|
189
|
-
throw createError("Only valid string value in options.depth.1 is '*'.");
|
|
190
|
-
}
|
|
191
|
-
const config = {
|
|
192
|
-
depth: freeze([options.depth[0] ?? 0, options.depth[1] ?? '*']),
|
|
193
|
-
exitEarly: false,
|
|
194
|
-
};
|
|
195
|
-
const initialArgs = [condition, callback, config, '', [], target, void 0, state];
|
|
196
|
-
if (getConfig().detectCircularReferences)
|
|
197
|
-
return circularDependencyTraversal(...initialArgs, referenceStack(), true);
|
|
198
|
-
return nonCircularDependencyTraversal(...initialArgs);
|
|
199
|
-
};
|
|
200
|
-
const createTraversal = (condition) => (target, callback, options, state) => traversal(target, condition, callback, options ?? { depth: [0, '*'] }, state ?? {});
|
|
201
|
-
const condition = (config, key, value, path) => !(path.length < config.depth[0] || config.depth[1] < path.length);
|
|
202
|
-
const traverseBetweenDepthRange = createTraversal(condition);
|
|
203
|
-
exports.createTraversal = createTraversal;
|
|
204
|
-
exports.getConfig = getConfig;
|
|
205
|
-
exports.getIterableTypes = getIterableTypes;
|
|
206
|
-
exports.getKeysFromIterable = getKeysFromIterable;
|
|
207
|
-
exports.getType = getType;
|
|
208
|
-
exports.isIterable = isIterable;
|
|
209
|
-
exports.isIterableType = isIterableType;
|
|
210
|
-
exports.isMarker = isMarker;
|
|
211
|
-
exports.marker = marker;
|
|
212
|
-
exports.referenceStack = referenceStack;
|
|
213
|
-
exports.registeredClasses = registeredClasses;
|
|
214
|
-
exports.registeredIterableClasses = registeredIterableClasses;
|
|
@@ -1,202 +0,0 @@
|
|
|
1
|
-
import { isArray } from '../immutable-api-utils/built-in-copy/array/index.esm.js';
|
|
2
|
-
import { createError } from '../immutable-api-utils/built-in-copy/error/index.esm.js';
|
|
3
|
-
import { keys, freeze } from '../immutable-api-utils/built-in-copy/object/index.esm.js';
|
|
4
|
-
import { createMap } from '../immutable-api-utils/built-in-copy/map/index.esm.js';
|
|
5
|
-
import { createDate } from '../immutable-api-utils/built-in-copy/date/index.esm.js';
|
|
6
|
-
import { round, random } from '../immutable-api-utils/built-in-copy/math/index.esm.js';
|
|
7
|
-
|
|
8
|
-
const isMarker = (text) => {
|
|
9
|
-
if (typeof text !== 'string' || !text.startsWith('__$'))
|
|
10
|
-
return false;
|
|
11
|
-
return /^__\$[0-9]+$/.test(text);
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
const registeredClasses = [];
|
|
15
|
-
const registeredIterableClasses = [
|
|
16
|
-
{
|
|
17
|
-
classRef: Array,
|
|
18
|
-
instantiate: () => [],
|
|
19
|
-
getKeys: (target) => {
|
|
20
|
-
const keysArray = keys(target);
|
|
21
|
-
if (getConfig().detectCircularReferences) {
|
|
22
|
-
return keysArray.filter((key) => !isMarker(key));
|
|
23
|
-
}
|
|
24
|
-
return keysArray;
|
|
25
|
-
},
|
|
26
|
-
read: (target, key) => target[key],
|
|
27
|
-
write: (target, value, key) => (target[key] = value),
|
|
28
|
-
remove: (target, value) => target.splice(value, 1),
|
|
29
|
-
},
|
|
30
|
-
{
|
|
31
|
-
classRef: Object,
|
|
32
|
-
instantiate: () => ({}),
|
|
33
|
-
getKeys: (target) => {
|
|
34
|
-
const keysArray = keys(target);
|
|
35
|
-
if (getConfig().detectCircularReferences) {
|
|
36
|
-
return keysArray.filter((key) => !isMarker(key));
|
|
37
|
-
}
|
|
38
|
-
return keysArray;
|
|
39
|
-
},
|
|
40
|
-
read: (target, key) => target[key],
|
|
41
|
-
write: (target, value, key) => (target[key] = value),
|
|
42
|
-
remove: (target, value) => delete target[value],
|
|
43
|
-
},
|
|
44
|
-
];
|
|
45
|
-
let samePositionOfOwnProperties = false;
|
|
46
|
-
let detectCircularReferences = false;
|
|
47
|
-
const getConfig = () => ({
|
|
48
|
-
samePositionOfOwnProperties,
|
|
49
|
-
detectCircularReferences,
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
const getKeysFromIterable = (target, dataType) => {
|
|
53
|
-
if (dataType === 'array')
|
|
54
|
-
dataType = Array.name;
|
|
55
|
-
if (dataType === 'object')
|
|
56
|
-
dataType = Object.name;
|
|
57
|
-
const iterableClass = registeredIterableClasses.find(({ classRef }) => dataType === classRef.name);
|
|
58
|
-
if (iterableClass === undefined)
|
|
59
|
-
return [];
|
|
60
|
-
return iterableClass.getKeys(target);
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
const getType = (target) => {
|
|
64
|
-
if (target === null)
|
|
65
|
-
return 'null';
|
|
66
|
-
const nativeDataType = typeof target;
|
|
67
|
-
if (nativeDataType === 'object') {
|
|
68
|
-
if (isArray(target))
|
|
69
|
-
return 'array';
|
|
70
|
-
for (const registeredClass of registeredClasses) {
|
|
71
|
-
if (target instanceof registeredClass)
|
|
72
|
-
return registeredClass.name;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
return nativeDataType;
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
const getIterableTypes = () => registeredIterableClasses.map(({ classRef }) => {
|
|
79
|
-
const name = classRef.name;
|
|
80
|
-
if (name === Object.name)
|
|
81
|
-
return 'object';
|
|
82
|
-
if (name === Array.name)
|
|
83
|
-
return 'array';
|
|
84
|
-
return name;
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
const isIterableType = (dataType) => getIterableTypes().includes(dataType);
|
|
88
|
-
|
|
89
|
-
const isIterable = (target) => isIterableType(getType(target));
|
|
90
|
-
|
|
91
|
-
const marker = () => {
|
|
92
|
-
const randomValue = round(random() * 10000000000000);
|
|
93
|
-
const sequential = createDate().getTime();
|
|
94
|
-
const unique = `${randomValue}${sequential}`;
|
|
95
|
-
const prefix = `__$`;
|
|
96
|
-
return `${prefix}${unique}`;
|
|
97
|
-
};
|
|
98
|
-
|
|
99
|
-
const referenceStack = () => {
|
|
100
|
-
const records = createMap();
|
|
101
|
-
const flag = marker();
|
|
102
|
-
const exists = (ref) => (isIterable(ref) ? flag in ref && records.has(ref[flag]) : false);
|
|
103
|
-
const add = (ref) => {
|
|
104
|
-
if (!isIterable(ref) || exists(ref))
|
|
105
|
-
return;
|
|
106
|
-
ref[flag] = Symbol();
|
|
107
|
-
records.set(ref[flag], [flag, ref, records.size]);
|
|
108
|
-
};
|
|
109
|
-
const lastSeen = (ref) => {
|
|
110
|
-
if (!isIterable(ref))
|
|
111
|
-
return null;
|
|
112
|
-
const record = records.get(ref[flag]);
|
|
113
|
-
return record ? record[2] - records.size : null;
|
|
114
|
-
};
|
|
115
|
-
const clear = () => (records.forEach(([key, ref]) => {
|
|
116
|
-
delete ref[key];
|
|
117
|
-
}),
|
|
118
|
-
records.clear());
|
|
119
|
-
return {
|
|
120
|
-
add: (ref) => add(ref),
|
|
121
|
-
exists: (ref) => exists(ref),
|
|
122
|
-
lastSeen: (ref) => lastSeen(ref),
|
|
123
|
-
clear: () => clear(),
|
|
124
|
-
get size() {
|
|
125
|
-
return records.size;
|
|
126
|
-
},
|
|
127
|
-
};
|
|
128
|
-
};
|
|
129
|
-
|
|
130
|
-
const errorMessage = (thing, type) => `Expected ${thing} to be ${type}.`;
|
|
131
|
-
const nextIterationDetails = (path, key, value) => ({
|
|
132
|
-
nextPath: [...path, key],
|
|
133
|
-
nextValue: value[key],
|
|
134
|
-
});
|
|
135
|
-
const circularDependencyTraversal = (condition, callback, config, key, path, value, parent, state, stack, root = false) => {
|
|
136
|
-
if (stack.exists(value))
|
|
137
|
-
return state;
|
|
138
|
-
const ok = condition(config, key, value, path, parent);
|
|
139
|
-
if (config.exitEarly)
|
|
140
|
-
return state;
|
|
141
|
-
if (ok)
|
|
142
|
-
callback(key, value, path, state, parent);
|
|
143
|
-
stack.add(value);
|
|
144
|
-
const type = getType(value);
|
|
145
|
-
if (!isIterableType(type))
|
|
146
|
-
return state;
|
|
147
|
-
const keys = getKeysFromIterable(value, type);
|
|
148
|
-
keys.forEach((key) => {
|
|
149
|
-
const { nextPath, nextValue } = nextIterationDetails(path, key, value);
|
|
150
|
-
circularDependencyTraversal(condition, callback, config, key, nextPath, nextValue, value, state, stack);
|
|
151
|
-
});
|
|
152
|
-
if (root)
|
|
153
|
-
stack.clear();
|
|
154
|
-
return state;
|
|
155
|
-
};
|
|
156
|
-
const nonCircularDependencyTraversal = (condition, callback, config, key, path, value, parent, state) => {
|
|
157
|
-
const ok = condition(config, key, value, path, parent);
|
|
158
|
-
if (config.exitEarly)
|
|
159
|
-
return state;
|
|
160
|
-
if (ok)
|
|
161
|
-
callback(key, value, path, state, parent);
|
|
162
|
-
const type = getType(value);
|
|
163
|
-
if (!isIterableType(type))
|
|
164
|
-
return state;
|
|
165
|
-
const keys = getKeysFromIterable(value, type);
|
|
166
|
-
keys.forEach((key) => {
|
|
167
|
-
const { nextPath, nextValue } = nextIterationDetails(path, key, value);
|
|
168
|
-
nonCircularDependencyTraversal(condition, callback, config, key, nextPath, nextValue, value, state);
|
|
169
|
-
});
|
|
170
|
-
return state;
|
|
171
|
-
};
|
|
172
|
-
const traversal = (target, condition, callback, options, state) => {
|
|
173
|
-
if (typeof callback !== 'function')
|
|
174
|
-
throw createError(errorMessage('callback', 'a function'));
|
|
175
|
-
if (!(typeof options === 'object' && !isArray(options)))
|
|
176
|
-
throw createError(errorMessage('options', 'an object'));
|
|
177
|
-
if (!isArray(options.depth))
|
|
178
|
-
throw createError(errorMessage('options.depth', 'an array'));
|
|
179
|
-
const [startDepth, maxDepth] = options.depth;
|
|
180
|
-
if (startDepth !== void 0 && typeof startDepth !== 'number')
|
|
181
|
-
throw createError(errorMessage('options.depth.0', 'a number'));
|
|
182
|
-
if (maxDepth !== void 0) {
|
|
183
|
-
const maxDepthType = typeof maxDepth;
|
|
184
|
-
if (!['number', 'string'].includes(maxDepthType))
|
|
185
|
-
throw createError(errorMessage('options.depth.1', 'a number or a string'));
|
|
186
|
-
if (maxDepthType === 'string' && maxDepth !== '*')
|
|
187
|
-
throw createError("Only valid string value in options.depth.1 is '*'.");
|
|
188
|
-
}
|
|
189
|
-
const config = {
|
|
190
|
-
depth: freeze([options.depth[0] ?? 0, options.depth[1] ?? '*']),
|
|
191
|
-
exitEarly: false,
|
|
192
|
-
};
|
|
193
|
-
const initialArgs = [condition, callback, config, '', [], target, void 0, state];
|
|
194
|
-
if (getConfig().detectCircularReferences)
|
|
195
|
-
return circularDependencyTraversal(...initialArgs, referenceStack(), true);
|
|
196
|
-
return nonCircularDependencyTraversal(...initialArgs);
|
|
197
|
-
};
|
|
198
|
-
const createTraversal = (condition) => (target, callback, options, state) => traversal(target, condition, callback, options ?? { depth: [0, '*'] }, state ?? {});
|
|
199
|
-
const condition = (config, key, value, path) => !(path.length < config.depth[0] || config.depth[1] < path.length);
|
|
200
|
-
const traverseBetweenDepthRange = createTraversal(condition);
|
|
201
|
-
|
|
202
|
-
export { createTraversal, getConfig, getIterableTypes, getKeysFromIterable, getType, isIterable, isIterableType, isMarker, marker, referenceStack, registeredClasses, registeredIterableClasses };
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|