tutuca 0.9.40 → 0.9.41
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/dist/tutuca-cli.js +74 -39
- package/package.json +6 -7
- package/skill/immutable-js/SKILL.md +79 -0
- package/skill/immutable-js/references/collection.md +346 -0
- package/skill/immutable-js/references/conversions.md +99 -0
- package/skill/immutable-js/references/deep-updates.md +172 -0
- package/skill/immutable-js/references/equality.md +95 -0
- package/skill/immutable-js/references/list.md +266 -0
- package/skill/immutable-js/references/map.md +300 -0
- package/skill/immutable-js/references/predicates.md +93 -0
- package/skill/immutable-js/references/range-repeat.md +55 -0
- package/skill/immutable-js/references/record.md +196 -0
- package/skill/immutable-js/references/seq.md +248 -0
- package/skill/immutable-js/references/set.md +270 -0
- package/skill/immutable-js/references/shallow-functional.md +99 -0
- package/skill/immutable-js/references/stack.md +210 -0
- package/skill/margaui/SKILL.md +101 -0
- package/skill/margaui/components/accordion.md +127 -0
- package/skill/margaui/components/alert.md +174 -0
- package/skill/margaui/components/avatar.md +220 -0
- package/skill/margaui/components/badge.md +193 -0
- package/skill/margaui/components/breadcrumbs.md +103 -0
- package/skill/margaui/components/button.md +322 -0
- package/skill/margaui/components/calendar.md +67 -0
- package/skill/margaui/components/card.md +373 -0
- package/skill/margaui/components/carousel.md +387 -0
- package/skill/margaui/components/chat.md +171 -0
- package/skill/margaui/components/checkbox.md +101 -0
- package/skill/margaui/components/collapse.md +172 -0
- package/skill/margaui/components/countdown.md +165 -0
- package/skill/margaui/components/diff.md +53 -0
- package/skill/margaui/components/divider.md +107 -0
- package/skill/margaui/components/dock.md +173 -0
- package/skill/margaui/components/drawer.md +184 -0
- package/skill/margaui/components/dropdown.md +388 -0
- package/skill/margaui/components/fab.md +346 -0
- package/skill/margaui/components/fieldset.md +88 -0
- package/skill/margaui/components/file-input.md +84 -0
- package/skill/margaui/components/filter.md +52 -0
- package/skill/margaui/components/footer.md +583 -0
- package/skill/margaui/components/hero.md +135 -0
- package/skill/margaui/components/hover-3d.md +129 -0
- package/skill/margaui/components/hover-gallery.md +49 -0
- package/skill/margaui/components/indicator.md +265 -0
- package/skill/margaui/components/input.md +389 -0
- package/skill/margaui/components/join.md +100 -0
- package/skill/margaui/components/kbd.md +127 -0
- package/skill/margaui/components/label.md +102 -0
- package/skill/margaui/components/link.md +96 -0
- package/skill/margaui/components/list.md +182 -0
- package/skill/margaui/components/loading.md +105 -0
- package/skill/margaui/components/mask.md +168 -0
- package/skill/margaui/components/menu.md +856 -0
- package/skill/margaui/components/mockup-browser.md +39 -0
- package/skill/margaui/components/mockup-code.md +81 -0
- package/skill/margaui/components/mockup-phone.md +39 -0
- package/skill/margaui/components/mockup-window.md +33 -0
- package/skill/margaui/components/modal.md +178 -0
- package/skill/margaui/components/navbar.md +282 -0
- package/skill/margaui/components/pagination.md +122 -0
- package/skill/margaui/components/progress.md +135 -0
- package/skill/margaui/components/radial-progress.md +67 -0
- package/skill/margaui/components/radio.md +133 -0
- package/skill/margaui/components/range.md +134 -0
- package/skill/margaui/components/rating.md +170 -0
- package/skill/margaui/components/select.md +225 -0
- package/skill/margaui/components/skeleton.md +64 -0
- package/skill/margaui/components/stack.md +142 -0
- package/skill/margaui/components/stat.md +254 -0
- package/skill/margaui/components/status.md +73 -0
- package/skill/margaui/components/steps.md +138 -0
- package/skill/margaui/components/swap.md +152 -0
- package/skill/margaui/components/tab.md +248 -0
- package/skill/margaui/components/table.md +1018 -0
- package/skill/margaui/components/text-rotate.md +91 -0
- package/skill/margaui/components/textarea.md +85 -0
- package/skill/margaui/components/theme-controller.md +266 -0
- package/skill/margaui/components/timeline.md +1356 -0
- package/skill/margaui/components/toast.md +165 -0
- package/skill/margaui/components/toggle.md +135 -0
- package/skill/margaui/components/tooltip.md +181 -0
- package/skill/margaui/components/validator.md +163 -0
- package/skill/{advanced.md → tutuca/advanced.md} +5 -0
- package/skill/{cli.md → tutuca/cli.md} +17 -0
- package/skill/{core.md → tutuca/core.md} +5 -0
- /package/skill/{SKILL.md → tutuca/SKILL.md} +0 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
Immutable.js conversions go in two directions: PARSE plain JS into Immutable with `fromJS`, and PROJECT Immutable back to plain JS with `toJS` / `toJSON` / `toArray` / `toObject` / specific-type converters (`toList`, `toMap`, `toSet`, ...). Reach for `fromJS` when you receive JSON or other plain data at a boundary. Reach for `toJS` only at boundaries (serialization, debugging, libraries that don't speak Immutable) — passing Immutable values around inside your code is preferred since `toJS` is recursive and allocates a fresh deep copy.
|
|
2
|
+
|
|
3
|
+
## fromJS
|
|
4
|
+
|
|
5
|
+
```ts
|
|
6
|
+
fromJS(jsValue, reviver?: (key, sequence, path) => unknown): unknown
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
Default behavior:
|
|
10
|
+
- Plain `Array` → `List`
|
|
11
|
+
- Plain `Object` (no custom prototype, own enumerable string keys) → `Map`
|
|
12
|
+
- Recurses into both
|
|
13
|
+
- Numbers, strings, booleans, `null`, `Date`, `RegExp`, JS `Map`/`Set`, custom class instances pass through unchanged
|
|
14
|
+
|
|
15
|
+
```js
|
|
16
|
+
import { fromJS } from 'immutable';
|
|
17
|
+
fromJS({ a: { b: [10, 20, 30] }, c: 40 });
|
|
18
|
+
// Map { a: Map { b: List [ 10, 20, 30 ] }, c: 40 }
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
The optional `reviver` is called bottom-up (deepest collection first) with each level wrapped as a `Seq.Keyed` (for objects) or `Seq.Indexed` (for arrays). It must return an Immutable Collection. The default reviver is effectively:
|
|
22
|
+
|
|
23
|
+
```js
|
|
24
|
+
(key, value) => (isKeyed(value) ? value.toMap() : value.toList());
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Override it to choose different bucket types — e.g. `OrderedMap` + `List`:
|
|
28
|
+
|
|
29
|
+
```js
|
|
30
|
+
import { fromJS, isKeyed } from 'immutable';
|
|
31
|
+
fromJS(payload, (_, value) =>
|
|
32
|
+
isKeyed(value) ? value.toOrderedMap() : value.toList()
|
|
33
|
+
);
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
The reviver also receives a `path` array (sequence of keys from the root) — useful for selectively converting only certain branches (e.g. leave `events` as a `List` but turn `index` into an `OrderedMap`).
|
|
37
|
+
|
|
38
|
+
## toJS / toJSON
|
|
39
|
+
|
|
40
|
+
- `toJS()` — recursively converts an Immutable value into plain JS. `Map`/`Record`/Keyed → object (string keys), `List`/`Stack`/Indexed → array, `Set`/`OrderedSet` → array.
|
|
41
|
+
- `toJSON()` — SHALLOW one-level conversion. The same shape (object vs array) but the values are still Immutable.
|
|
42
|
+
- `JSON.stringify(immutableValue)` works out of the box: each node's `toJSON` is invoked recursively by the serializer, so the resulting JSON string IS deeply plain.
|
|
43
|
+
- `Record#toJSON()` returns a plain object with the record's defined keys (no prototype).
|
|
44
|
+
|
|
45
|
+
```js
|
|
46
|
+
import { Map, List } from 'immutable';
|
|
47
|
+
const m = Map({ items: List([1, 2, 3]) });
|
|
48
|
+
m.toJS(); // { items: [1, 2, 3] } (deep)
|
|
49
|
+
m.toJSON(); // { items: List [ 1, 2, 3 ] } (shallow)
|
|
50
|
+
JSON.stringify(m); // '{"items":[1,2,3]}' (deep, via toJSON recursion)
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Per-type converters
|
|
54
|
+
|
|
55
|
+
Shallow conversions to plain JS containers:
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
toArray(): Array<V> | Array<[K, V]> // Keyed → entries; Indexed/Set → values
|
|
59
|
+
toObject(): { [key: string]: V } // Keyed only; coerces keys to strings
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Re-bucket into another Immutable collection (the source's keys may or may not survive — see notes):
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
toList(): List<V> // discards keys (Map → values only)
|
|
66
|
+
toMap(): Map<K, V> // requires hashable keys; throws otherwise
|
|
67
|
+
toOrderedMap(): OrderedMap<K, V> // preserves iteration order
|
|
68
|
+
toSet(): Set<V> // discards keys; requires hashable values
|
|
69
|
+
toOrderedSet(): OrderedSet<V> // preserves iteration order
|
|
70
|
+
toStack(): Stack<V> // discards keys
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Lazy `Seq` variants (no work until iterated):
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
toSeq(): Seq<K, V> // same kind as the source
|
|
77
|
+
toKeyedSeq(): Seq.Keyed<K, V> // for Indexed: indices become keys
|
|
78
|
+
toIndexedSeq(): Seq.Indexed<V> // discards keys
|
|
79
|
+
toSetSeq(): Seq.Set<V> // discards keys
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
These are equivalent to passing the collection to the corresponding constructor (`List(coll)`, `Map(coll)`, ...) but read better in chains and have one important difference: `List(map)` produces a list of `[key, value]` entry tuples, while `map.toList()` produces a list of values only.
|
|
83
|
+
|
|
84
|
+
## Gotchas
|
|
85
|
+
|
|
86
|
+
- `fromJS` does NOT convert `Date`, JS `Map`/`Set`, `RegExp`, typed arrays, or custom class instances — they pass through. Use a `reviver` if you need to convert them.
|
|
87
|
+
- `fromJS` only treats objects with the default `Object.prototype` as plain — anything with a custom prototype is left alone. This is usually what you want, but means subclasses of `Object` won't be deepened.
|
|
88
|
+
- `toJS` is recursive and allocates a fresh deep copy on every call. On large structures it is expensive — iterate Immutable values directly rather than calling `.toJS()` in render paths or hot loops.
|
|
89
|
+
- `Map#toList()` discards keys (values-only). If you want pairs, use `map.entrySeq().toList()` or `map.toIndexedSeq()` over `entrySeq`.
|
|
90
|
+
- `Map#toArray()` (and other Keyed `toArray()`) returns `[key, value]` tuples, not values — use `valueSeq().toArray()` for a flat values array.
|
|
91
|
+
- Round-tripping `fromJS(value).toJS()` produces a structurally similar object but not necessarily identical: property iteration order may change, and any non-plain instances on the input round-trip as the same reference (since `fromJS` left them alone).
|
|
92
|
+
- `JSON.stringify(immutable)` works without explicit conversion — `toJSON` is wired up on every collection. No need to call `.toJS()` first.
|
|
93
|
+
- `toMap()` and `toSet()` throw at runtime if the values/keys are not hashable (e.g. mutable JS objects). `toOrderedMap`/`toOrderedSet` have the same constraint but preserve insertion order.
|
|
94
|
+
|
|
95
|
+
## See also
|
|
96
|
+
|
|
97
|
+
- `references/deep-updates.md` — `getIn`/`setIn`/`updateIn`/`mergeDeep` for working without converting back to JS.
|
|
98
|
+
- `references/list.md`, `references/map.md`, `references/set.md` — per-type construction and method details.
|
|
99
|
+
- `references/predicates.md` — `isImmutable`, `isKeyed`, `isIndexed` (used in `fromJS` revivers).
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
When you have nested data, these helpers update by path without writing the boilerplate yourself. Each returns a new structure with structural sharing for the unchanged parts. Available both as top-level functions imported from `immutable` (which also accept plain JS objects/arrays) and as instance methods on every Immutable collection. The instance forms (`map.setIn(...)`, `list.updateIn(...)`, etc.) have identical semantics on Immutable inputs.
|
|
2
|
+
|
|
3
|
+
## Paths
|
|
4
|
+
|
|
5
|
+
- A path is any iterable of keys/indices — most code uses an `Array`, but any `Iterable` works.
|
|
6
|
+
- Use numeric indices for `List`/`Array` segments and string keys for `Map`/`Record`/object segments. Keys are matched exactly (no negative-index resolution like `List.get(-1)` does).
|
|
7
|
+
- For `setIn`/`updateIn`/`mergeIn`, missing intermediate keys are auto-created as empty `Map`s to fill out the path. If you want a `List` at some level, initialize it explicitly first.
|
|
8
|
+
- `getIn`/`hasIn` never mutate or extend — a missing intermediate just yields `notSetValue` / `false`.
|
|
9
|
+
- All functions return the same identity (`===`) when no change occurs (e.g. `setIn` to the existing value).
|
|
10
|
+
|
|
11
|
+
## getIn
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
getIn(collection, keyPath, notSetValue?): any
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Walks `keyPath` from `collection` and returns the value found, or `notSetValue` (default `undefined`) if any segment is missing.
|
|
18
|
+
|
|
19
|
+
```js
|
|
20
|
+
getIn({ x: { y: { z: 123 } } }, ['x', 'y', 'z']); // => 123
|
|
21
|
+
getIn({ x: { y: { z: 123 } } }, ['x', 'q', 'p'], 'fallback'); // => 'fallback'
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## hasIn
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
hasIn(collection, keyPath): boolean
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Returns `true` iff every segment of `keyPath` resolves. Distinguishes "key absent" from "key present but `undefined`", unlike `getIn(...) !== undefined`.
|
|
31
|
+
|
|
32
|
+
```js
|
|
33
|
+
hasIn({ x: { y: { z: 123 } } }, ['x', 'y', 'z']); // => true
|
|
34
|
+
hasIn({ x: { y: { z: 123 } } }, ['x', 'q', 'p']); // => false
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## setIn
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
setIn(collection: C, keyPath: Iterable, value: any): C
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Returns a copy of `collection` with the value at `keyPath` replaced by `value`. Missing intermediate keys are filled in as empty `Map`s.
|
|
44
|
+
|
|
45
|
+
```js
|
|
46
|
+
setIn({ x: { y: { z: 123 } } }, ['x', 'y', 'z'], 456);
|
|
47
|
+
// => { x: { y: { z: 456 } } }
|
|
48
|
+
|
|
49
|
+
setIn(Map(), ['a', 'b', 'c'], 1);
|
|
50
|
+
// => Map { "a": Map { "b": Map { "c": 1 } } }
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## updateIn
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
updateIn(collection, keyPath, updater)
|
|
57
|
+
updateIn(collection, keyPath, notSetValue, updater)
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Returns a copy where the value at `keyPath` is replaced by `updater(currentValue)`. With four arguments, `notSetValue` is passed to `updater` when the path is missing (otherwise `updater` receives `undefined`). Like `setIn`, missing intermediates become empty `Map`s.
|
|
61
|
+
|
|
62
|
+
```js
|
|
63
|
+
// 3-arg: updater receives undefined when path is missing
|
|
64
|
+
updateIn(Map(), ['hits'], n => (n || 0) + 1);
|
|
65
|
+
// => Map { "hits": 1 }
|
|
66
|
+
|
|
67
|
+
// 4-arg: notSetValue is passed in when path is missing
|
|
68
|
+
updateIn(Map({ x: { y: 10 } }), ['x', 'y'], 0, n => n + 1);
|
|
69
|
+
// => Map { "x": { "y": 11 } }
|
|
70
|
+
updateIn(Map(), ['x', 'y'], 0, n => n + 1);
|
|
71
|
+
// => Map { "x": Map { "y": 1 } }
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## removeIn (alias deleteIn)
|
|
75
|
+
|
|
76
|
+
```ts
|
|
77
|
+
removeIn(collection: C, keyPath: Iterable): C
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Returns a copy with the entry at `keyPath` removed. Intermediate containers are left in place even if they become empty.
|
|
81
|
+
|
|
82
|
+
```js
|
|
83
|
+
removeIn({ x: { y: { z: 123 } } }, ['x', 'y', 'z']);
|
|
84
|
+
// => { x: { y: {} } }
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## merge
|
|
88
|
+
|
|
89
|
+
```ts
|
|
90
|
+
merge<C>(collection: C, ...sources): C
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Shallow non-mutating merge: each source's keys overwrite `collection`'s at the top level only. For plain objects this behaves like `Object.assign({}, target, ...sources)` but never mutates; for `Map`-like targets it merges entries.
|
|
94
|
+
|
|
95
|
+
```js
|
|
96
|
+
merge({ x: 123, y: 456 }, { y: 789 });
|
|
97
|
+
// => { x: 123, y: 789 }
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## mergeWith
|
|
101
|
+
|
|
102
|
+
```ts
|
|
103
|
+
mergeWith<C>(
|
|
104
|
+
merger: (oldVal, newVal, key) => any,
|
|
105
|
+
collection: C,
|
|
106
|
+
...sources
|
|
107
|
+
): C
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Like `merge`, but `merger(oldVal, newVal, key)` resolves every collision (called only when both sides have the key).
|
|
111
|
+
|
|
112
|
+
```js
|
|
113
|
+
mergeWith(
|
|
114
|
+
(oldVal, newVal) => oldVal + newVal,
|
|
115
|
+
{ x: 123, y: 456 },
|
|
116
|
+
{ y: 789, z: 'abc' }
|
|
117
|
+
);
|
|
118
|
+
// => { x: 123, y: 1245, z: 'abc' }
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## mergeDeep
|
|
122
|
+
|
|
123
|
+
```ts
|
|
124
|
+
mergeDeep<C>(collection: C, ...sources): C
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Recursive merge. At each key: if both old and new values are "compatible" collections in the same category (keyed: `Map`/`Record`/object, indexed: `List`/`Array`, set-like: `Set`), they are merged together; otherwise the new value replaces the old. Indexed and set-like values are merged via `concat()`/`union()` — they do NOT recurse element-wise. Mixing categories at a key (e.g. `List` vs `Map`) replaces.
|
|
128
|
+
|
|
129
|
+
```js
|
|
130
|
+
mergeDeep({ x: { y: 123 } }, { x: { z: 456 } });
|
|
131
|
+
// => { x: { y: 123, z: 456 } }
|
|
132
|
+
|
|
133
|
+
mergeDeep({ xs: [1, 2] }, { xs: [3, 4] });
|
|
134
|
+
// => { xs: [1, 2, 3, 4] } // concat, NOT element-wise merge
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## mergeDeepWith
|
|
138
|
+
|
|
139
|
+
```ts
|
|
140
|
+
mergeDeepWith<C>(
|
|
141
|
+
merger: (oldVal, newVal, key) => any,
|
|
142
|
+
collection: C,
|
|
143
|
+
...sources
|
|
144
|
+
): C
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Like `mergeDeep`, but at any leaf collision (or when the two sides are in incompatible categories), `merger(oldVal, newVal, key)` decides the resulting value.
|
|
148
|
+
|
|
149
|
+
```js
|
|
150
|
+
mergeDeepWith(
|
|
151
|
+
(oldVal, newVal) => oldVal + newVal,
|
|
152
|
+
{ x: { y: 123 } },
|
|
153
|
+
{ x: { y: 456 } }
|
|
154
|
+
);
|
|
155
|
+
// => { x: { y: 579 } }
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Gotchas
|
|
159
|
+
|
|
160
|
+
- `setIn`/`updateIn`/`mergeIn` create missing intermediates as empty `Map`s. If a layer should be a `List`, build it yourself (e.g. `setIn(state, ['items'], List())` first) — paths cannot signal which container type to materialize.
|
|
161
|
+
- `mergeDeep` does NOT element-merge `List`s/`Array`s — same-key indexed values are concatenated, and `Set`s are unioned. To deep-merge by index, write a custom `mergeDeepWith` merger.
|
|
162
|
+
- A category mismatch at a key (e.g. existing `List`, incoming `Map`) replaces under `mergeDeep`; only `mergeDeepWith` lets you intervene.
|
|
163
|
+
- Top-level functional forms accept plain JS as the target and return the same kind back (object in / object out, `Map` in / `Map` out). The instance methods are only on Immutable collections.
|
|
164
|
+
- All operations are identity-preserving on no-op: `setIn(c, path, c.getIn(path)) === c`, `merge(c) === c` when nothing changes.
|
|
165
|
+
- `getIn`/`hasIn` perform exact key lookups. `getIn(list, [-1])` does not return the last element — use `list.last()`.
|
|
166
|
+
|
|
167
|
+
## See also
|
|
168
|
+
|
|
169
|
+
- `list.md`, `map.md` — instance variants and additional `*In` methods (`mergeIn`, `mergeDeepIn`).
|
|
170
|
+
- `record.md` — path access on `Record` respects declared fields.
|
|
171
|
+
- `conversions.md` — when mixing JS and Immutable inputs across these helpers.
|
|
172
|
+
- `shallow-functional.md` — single-level versions (`get`, `set`, `update`, `remove`, `has`).
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
Immutable.js treats collections as VALUES, not references: two distinct `Map({a: 1})` instances are equal even though `===` says otherwise. This is implemented via two protocols, `equals(other): boolean` and `hashCode(): number`, together forming the `ValueObject` interface. The top-level `is(a, b)` function dispatches to the appropriate comparison. Anything that implements both methods becomes a `ValueObject` and can be used as a `Map`/`OrderedMap` key or a `Set`/`OrderedSet` member with value-equality semantics — so two structurally equal custom objects collapse to a single entry, and lookup works with any equivalent instance.
|
|
2
|
+
|
|
3
|
+
## is
|
|
4
|
+
|
|
5
|
+
### is
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
is(first: unknown, second: unknown): boolean
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Value-equality check. Returns `true` for SameValue semantics (handles `NaN === NaN` as true), but unlike `Object.is` treats `0` and `-0` as equal (matching ES6 `Map` key equality). For `ValueObject` arguments dispatches to `first.equals(second)`. For primitives and non-`ValueObject` objects falls back to `Object.is`-style comparison.
|
|
12
|
+
|
|
13
|
+
```js
|
|
14
|
+
import { Map, is } from 'immutable';
|
|
15
|
+
const a = Map({ x: 1, y: 2 });
|
|
16
|
+
const b = Map({ x: 1, y: 2 });
|
|
17
|
+
a !== b; // true — distinct instances
|
|
18
|
+
Object.is(a, b); // false
|
|
19
|
+
is(a, b); // true — value-equal
|
|
20
|
+
a.equals(b); // true — same as is(a, b)
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Used internally throughout Immutable.js for `Map` key equality, `Set` membership, `.includes()`, `.indexOf()`, etc.
|
|
24
|
+
|
|
25
|
+
## hash
|
|
26
|
+
|
|
27
|
+
### hash
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
hash(value: unknown): number
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Returns a 31-bit integer hash for any value. For `ValueObject`s, calls `value.hashCode()`. For primitives (strings, numbers, booleans, `null`, `undefined`), produces a deterministic per-value hash. For plain objects, plain arrays, `Date`, etc. that don't implement `hashCode`, generates a unique per-instance hash and memoizes it on the object — so the hash represents referential identity (stable across mutations), not value equality.
|
|
34
|
+
|
|
35
|
+
Used internally by `Map`/`Set` for hash bucketing. Balances speed and collision avoidance; not cryptographically secure. _New in v4.0._
|
|
36
|
+
|
|
37
|
+
## ValueObject
|
|
38
|
+
|
|
39
|
+
### ValueObject
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
interface ValueObject {
|
|
43
|
+
equals(other: unknown): boolean;
|
|
44
|
+
hashCode(): number;
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
The interface to implement so a custom class behaves as a value: usable as a `Map`/`OrderedMap` key, in a `Set`/`OrderedSet`, and comparable via `is()`. All Immutable collections (`List`, `Map`, `Set`, `Record`, etc.) already implement it.
|
|
49
|
+
|
|
50
|
+
Contract:
|
|
51
|
+
|
|
52
|
+
- `a.equals(b) === true` MUST imply `a.hashCode() === b.hashCode()` (the converse is not required — hash collisions are allowed).
|
|
53
|
+
- `hashCode()` MUST return a Uint32. Idiomatic guard: `return myHash | 0`.
|
|
54
|
+
- `hashCode()` is not guaranteed to be called before `equals()`; lookups always verify via `equals()`.
|
|
55
|
+
|
|
56
|
+
```js
|
|
57
|
+
import { Set, hash } from 'immutable';
|
|
58
|
+
|
|
59
|
+
class Point {
|
|
60
|
+
constructor(x, y) { this.x = x; this.y = y; }
|
|
61
|
+
equals(other) {
|
|
62
|
+
return other instanceof Point && other.x === this.x && other.y === this.y;
|
|
63
|
+
}
|
|
64
|
+
hashCode() {
|
|
65
|
+
return (hash(this.x) * 31 + hash(this.y)) | 0;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const s = Set([new Point(1, 2)]);
|
|
70
|
+
s.has(new Point(1, 2)); // true — different instance, value-equal
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## isValueObject
|
|
74
|
+
|
|
75
|
+
### isValueObject
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
isValueObject(maybeValue: unknown): maybeValue is ValueObject
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Returns `true` iff `maybeValue` is a JavaScript object that has BOTH `equals` and `hashCode` methods. Any two value objects can be compared with `is()` and used as `Map` keys or `Set` members.
|
|
82
|
+
|
|
83
|
+
## Reference identity vs value equality
|
|
84
|
+
|
|
85
|
+
- All Immutable collections implement `ValueObject`, so `is(a, b)` and `a.equals(b)` give value-equality.
|
|
86
|
+
- Persistent operations that don't change content return the SAME identity: `map.set('k', v)` where `map.get('k') === v` returns `map` itself (`===`). This makes `===` a valid fast-path for "definitely unchanged" — useful for `React.memo`, `shouldComponentUpdate`, and memoization.
|
|
87
|
+
- JavaScript's `===` between two distinct Immutable collections with equal content is `false`. This is intentional: cheap reference checks remain cheap, and value-equality is opt-in via `is()` / `.equals()`.
|
|
88
|
+
- Rule of thumb: use `===` to detect "this reference changed"; use `is()` / `.equals()` to ask "is the content the same?".
|
|
89
|
+
|
|
90
|
+
## See also
|
|
91
|
+
|
|
92
|
+
- `map.md`, `set.md` — collections whose key/member identity is governed by `is`/`hashCode`.
|
|
93
|
+
- `record.md` — `Record` instances are `ValueObject`s, equal when their fields are value-equal.
|
|
94
|
+
- `predicates.md` — `isImmutable`, `isCollection`, etc. for runtime type checks.
|
|
95
|
+
- `conversions.md` — `fromJS`/`toJS` boundary where value identity is created/lost.
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
`List` is an ordered, indexed, dense, immutable collection — the Immutable.js analogue of a JavaScript Array. It is fully persistent with `O(log32 N)` `get`/`set` and `O(1)` `push`/`pop`, and it implements Deque (efficient `unshift`/`shift` as well). Reach for `List` when you need an ordered sequence keyed by integer index; prefer `Map` for keyed data, `Set`/`OrderedSet` for uniqueness, and `Stack` when you only push/pop one end and want amortised `O(1)` random access via head. Unlike a JS Array, `List` does not distinguish "unset" from `undefined`: `forEach` visits every index from `0` to `size`.
|
|
2
|
+
|
|
3
|
+
## Construction
|
|
4
|
+
|
|
5
|
+
```ts
|
|
6
|
+
import { List } from 'immutable';
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
### List / List.of / List.isList
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
function List<T>(collection?: Iterable<T> | ArrayLike<T>): List<T>;
|
|
13
|
+
function List.of<T>(...values: Array<T>): List<T>;
|
|
14
|
+
function List.isList(maybeList: unknown): maybeList is List<unknown>;
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Factory function (no `new`). `List.of` is variadic; values are not converted. See also `predicates.md`.
|
|
18
|
+
|
|
19
|
+
```js
|
|
20
|
+
List(); // => List []
|
|
21
|
+
List([1, 2, 3, 4]); // => List [ 1, 2, 3, 4 ]
|
|
22
|
+
List.of('a', 'b'); // => List [ "a", "b" ]
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Reading
|
|
26
|
+
|
|
27
|
+
### size / get / has / includes (alias `contains`) / first / last / indexOf / lastIndexOf
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
readonly size: number;
|
|
31
|
+
get(index: number): T | undefined;
|
|
32
|
+
get<NSV>(index: number, notSetValue: NSV): T | NSV;
|
|
33
|
+
has(index: number): boolean;
|
|
34
|
+
includes(value: T): boolean;
|
|
35
|
+
first<NSV = undefined>(notSetValue?: NSV): T | NSV;
|
|
36
|
+
last<NSV = undefined>(notSetValue?: NSV): T | NSV;
|
|
37
|
+
indexOf(value: T): number;
|
|
38
|
+
lastIndexOf(value: T): number;
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Negative indices on `get` count from the end (`get(-1)` is the last item). `includes` uses `Immutable.is` for equality. `indexOf`/`lastIndexOf` return `-1` if not found.
|
|
42
|
+
|
|
43
|
+
### find / findLast / findIndex / findLastIndex / findEntry / findLastEntry / findKey / findLastKey
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
find(predicate, context?, notSetValue?): T | undefined;
|
|
47
|
+
findLast(predicate, context?, notSetValue?): T | undefined;
|
|
48
|
+
findIndex(predicate, context?): number;
|
|
49
|
+
findLastIndex(predicate, context?): number;
|
|
50
|
+
findEntry(predicate, context?): [number, T] | undefined;
|
|
51
|
+
findLastEntry(predicate, context?): [number, T] | undefined;
|
|
52
|
+
findKey(predicate, context?): number | undefined;
|
|
53
|
+
findLastKey(predicate, context?): number | undefined;
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
`predicate: (value: T, index: number, iter: this) => boolean`. `*Last` variants iterate in reverse.
|
|
57
|
+
|
|
58
|
+
### keyOf / lastKeyOf / max / min / maxBy / minBy
|
|
59
|
+
|
|
60
|
+
```ts
|
|
61
|
+
keyOf(searchValue: T): number | undefined;
|
|
62
|
+
lastKeyOf(searchValue: T): number | undefined;
|
|
63
|
+
max(comparator?: (a: T, b: T) => number): T | undefined;
|
|
64
|
+
min(comparator?: (a: T, b: T) => number): T | undefined;
|
|
65
|
+
maxBy<C>(mapper: (value: T, key: number, iter: this) => C, comparator?: (a: C, b: C) => number): T | undefined;
|
|
66
|
+
minBy<C>(mapper: (value: T, key: number, iter: this) => C, comparator?: (a: C, b: C) => number): T | undefined;
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Persistent changes
|
|
70
|
+
|
|
71
|
+
### set
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
set(index: number, value: T): List<T>;
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Negative `index` is allowed. Setting beyond `size` grows the List (gaps become `undefined`). `List().set(50000, 'v').size === 50001`.
|
|
78
|
+
|
|
79
|
+
### delete (alias `remove`)
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
delete(index: number): List<T>;
|
|
83
|
+
remove(index: number): List<T>;
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Re-indexes successors; `O(N)`. Cannot be used in `withMutations`.
|
|
87
|
+
|
|
88
|
+
### insert
|
|
89
|
+
|
|
90
|
+
```ts
|
|
91
|
+
insert(index: number, value: T): List<T>;
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Equivalent to `splice(index, 0, value)`. `O(N)`. Cannot be used in `withMutations`.
|
|
95
|
+
|
|
96
|
+
### clear
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
clear(): List<T>;
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### push / pop / unshift / shift
|
|
103
|
+
|
|
104
|
+
```ts
|
|
105
|
+
push(...values: Array<T>): List<T>;
|
|
106
|
+
pop(): List<T>;
|
|
107
|
+
unshift(...values: Array<T>): List<T>;
|
|
108
|
+
shift(): List<T>;
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
`pop`/`shift` return the trimmed List, not the removed value (use `last()`/`first()`).
|
|
112
|
+
|
|
113
|
+
### update
|
|
114
|
+
|
|
115
|
+
```ts
|
|
116
|
+
update(index: number, notSetValue: T, updater: (value: T) => T): this;
|
|
117
|
+
update(index: number, updater: (value: T | undefined) => T | undefined): this;
|
|
118
|
+
update<R>(updater: (value: this) => R): R;
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
The single-argument form is a "thru" / pipe: `list.update(sum)` calls `sum(list)`. See `shallow-functional.md`.
|
|
122
|
+
|
|
123
|
+
### setSize
|
|
124
|
+
|
|
125
|
+
```ts
|
|
126
|
+
setSize(size: number): List<T>;
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Truncates or pads with `undefined`. Pair with `withMutations` when the final size is known up front for faster construction.
|
|
130
|
+
|
|
131
|
+
## Deep persistent changes
|
|
132
|
+
|
|
133
|
+
See `deep-updates.md` for full semantics, key-path conventions, and interaction with nested plain JS objects/arrays.
|
|
134
|
+
|
|
135
|
+
### setIn / deleteIn (alias `removeIn`) / updateIn / mergeIn / mergeDeepIn
|
|
136
|
+
|
|
137
|
+
```ts
|
|
138
|
+
setIn(keyPath: Iterable<unknown>, value: unknown): this;
|
|
139
|
+
deleteIn(keyPath: Iterable<unknown>): this;
|
|
140
|
+
removeIn(keyPath: Iterable<unknown>): this;
|
|
141
|
+
updateIn(keyPath: Iterable<unknown>, notSetValue: unknown, updater: (value: unknown) => unknown): this;
|
|
142
|
+
updateIn(keyPath: Iterable<unknown>, updater: (value: unknown) => unknown): this;
|
|
143
|
+
mergeIn(keyPath: Iterable<unknown>, ...collections: Array<unknown>): this;
|
|
144
|
+
mergeDeepIn(keyPath: Iterable<unknown>, ...collections: Array<unknown>): this;
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Numeric keys index into the List; string keys traverse nested Maps/objects. `deleteIn` cannot be used in `withMutations`; the others can.
|
|
148
|
+
|
|
149
|
+
## Sequence algorithms
|
|
150
|
+
|
|
151
|
+
### concat (alias `merge`) / map / flatMap
|
|
152
|
+
|
|
153
|
+
```ts
|
|
154
|
+
concat<C>(...valuesOrCollections: Array<Iterable<C> | C>): List<T | C>;
|
|
155
|
+
map<M>(mapper: (value: T, key: number, iter: this) => M, context?: unknown): List<M>;
|
|
156
|
+
flatMap<M>(mapper: (value: T, key: number, iter: this) => Iterable<M>, context?: unknown): List<M>;
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
`flatMap` is equivalent to `list.map(...).flatten(true)`.
|
|
160
|
+
|
|
161
|
+
### filter / filterNot / partition
|
|
162
|
+
|
|
163
|
+
```ts
|
|
164
|
+
filter<F extends T>(predicate: (value: T, index: number, iter: this) => value is F, context?: unknown): List<F>;
|
|
165
|
+
filter(predicate: (value: T, index: number, iter: this) => unknown, context?: unknown): this;
|
|
166
|
+
filterNot(predicate: (value: T, index: number, iter: this) => boolean, context?: unknown): this;
|
|
167
|
+
partition<F extends T, C>(predicate: (this: C, value: T, index: number, iter: this) => value is F, context?: C): [List<T>, List<F>];
|
|
168
|
+
partition<C>(predicate: (this: C, value: T, index: number, iter: this) => unknown, context?: C): [this, this];
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
`filter`/`filterNot` always return a new instance. `partition` returns `[falses, trues]`.
|
|
172
|
+
|
|
173
|
+
### zip / zipAll / zipWith
|
|
174
|
+
|
|
175
|
+
```ts
|
|
176
|
+
zip<U>(other: Collection<unknown, U>): List<[T, U]>;
|
|
177
|
+
zipAll<U>(other: Collection<unknown, U>): List<[T, U]>;
|
|
178
|
+
zipWith<U, Z>(zipper: (value: T, otherValue: U) => Z, otherCollection: Collection<unknown, U>): List<Z>;
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
`zip` stops at the shortest input; `zipAll` pads shorter inputs with `undefined`.
|
|
182
|
+
|
|
183
|
+
### slice / reverse / sort / sortBy / groupBy
|
|
184
|
+
|
|
185
|
+
```ts
|
|
186
|
+
slice(begin?: number, end?: number): this;
|
|
187
|
+
reverse(): this;
|
|
188
|
+
sort(comparator?: (a: T, b: T) => PairSorting | number): this;
|
|
189
|
+
sortBy<C>(mapper: (value: T, key: number, iter: this) => C, comparator?: (a: C, b: C) => number): this;
|
|
190
|
+
groupBy<G>(grouper: (value: T, index: number, iter: this) => G, context?: unknown): Map<G, this>;
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
`slice` accepts negative indices (inherited from `Collection.Indexed`). `sort`/`sortBy` are stable, eager, and always return a new instance. `groupBy` is also eager.
|
|
194
|
+
|
|
195
|
+
### Other (inherited from `Collection.Indexed`)
|
|
196
|
+
|
|
197
|
+
`interpose(separator)`, `interleave(...collections)`, `splice(index, removeNum, ...values)`, `flatten(depth?)`, `shuffle(random?)`, `mapKeys`, `mapEntries`.
|
|
198
|
+
|
|
199
|
+
## Conversion
|
|
200
|
+
|
|
201
|
+
See `conversions.md` for `toJS` deep-conversion rules and the relationship with `toJSON` / `JSON.stringify`.
|
|
202
|
+
|
|
203
|
+
### toArray / toJS / toJSON
|
|
204
|
+
|
|
205
|
+
```ts
|
|
206
|
+
toArray(): Array<T>; // shallow
|
|
207
|
+
toJS(): Array<DeepCopy<T>>; // deep — recursively unwraps nested Immutable collections
|
|
208
|
+
toJSON(): Array<T>; // shallow; called by JSON.stringify
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### toSeq / toIndexedSeq / toKeyedSeq / toSetSeq
|
|
212
|
+
|
|
213
|
+
```ts
|
|
214
|
+
toSeq(): Seq.Indexed<T>;
|
|
215
|
+
toIndexedSeq(): Seq.Indexed<T>;
|
|
216
|
+
toKeyedSeq(): Seq.Keyed<number, T>;
|
|
217
|
+
toSetSeq(): Seq.Set<T>;
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
`toKeyedSeq` preserves `[index, value]` pairs through later filter/map.
|
|
221
|
+
|
|
222
|
+
### asImmutable / asMutable
|
|
223
|
+
|
|
224
|
+
```ts
|
|
225
|
+
asImmutable(): this;
|
|
226
|
+
asMutable(): this;
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
See "Mutation batching".
|
|
230
|
+
|
|
231
|
+
## Mutation batching
|
|
232
|
+
|
|
233
|
+
`withMutations` returns a transient mutable copy; once the callback returns, the result is frozen back into a regular persistent `List`. Useful when chaining many updates to avoid intermediate allocations.
|
|
234
|
+
|
|
235
|
+
### withMutations
|
|
236
|
+
|
|
237
|
+
```ts
|
|
238
|
+
withMutations(mutator: (mutable: this) => unknown): this;
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
Not every method is safe inside the mutator — methods that re-index (`delete`, `insert`, `splice`, `interleave`, `deleteIn`) are unsafe. Each method's signature in this file notes whether it is safe.
|
|
242
|
+
|
|
243
|
+
### asMutable / asImmutable
|
|
244
|
+
|
|
245
|
+
```ts
|
|
246
|
+
asMutable(): this;
|
|
247
|
+
asImmutable(): this;
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
Alternative to `withMutations` when you want explicit begin/end calls.
|
|
251
|
+
|
|
252
|
+
### wasAltered
|
|
253
|
+
|
|
254
|
+
```ts
|
|
255
|
+
wasAltered(): boolean;
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
True if a transient mutation actually changed the collection.
|
|
259
|
+
|
|
260
|
+
## See also
|
|
261
|
+
|
|
262
|
+
- `Collection.Indexed` for inherited iteration, search, and reduction methods (`forEach`, `reduce`, `every`, `some`, `count`, `keys`, `values`, `entries`, etc.)
|
|
263
|
+
- `deep-updates.md` for `setIn` / `updateIn` / `mergeIn` / `mergeDeepIn` semantics
|
|
264
|
+
- `shallow-functional.md` for `update`-as-pipe and other functional patterns
|
|
265
|
+
- `conversions.md` for `toJS` vs `toJSON` vs `toArray`
|
|
266
|
+
- `predicates.md` for `List.isList` and other type guards
|