articulated 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +9 -0
- package/README.md +106 -0
- package/build/commonjs/id.d.ts +61 -0
- package/build/commonjs/id.js +39 -0
- package/build/commonjs/id.js.map +1 -0
- package/build/commonjs/id_list.d.ts +226 -0
- package/build/commonjs/id_list.js +426 -0
- package/build/commonjs/id_list.js.map +1 -0
- package/build/commonjs/index.d.ts +3 -0
- package/build/commonjs/index.js +20 -0
- package/build/commonjs/index.js.map +1 -0
- package/build/commonjs/saved_id_list.d.ts +13 -0
- package/build/commonjs/saved_id_list.js +3 -0
- package/build/commonjs/saved_id_list.js.map +1 -0
- package/build/esm/id.d.ts +61 -0
- package/build/esm/id.js +34 -0
- package/build/esm/id.js.map +1 -0
- package/build/esm/id_list.d.ts +226 -0
- package/build/esm/id_list.js +421 -0
- package/build/esm/id_list.js.map +1 -0
- package/build/esm/index.d.ts +3 -0
- package/build/esm/index.js +4 -0
- package/build/esm/index.js.map +1 -0
- package/build/esm/saved_id_list.d.ts +13 -0
- package/build/esm/saved_id_list.js +2 -0
- package/build/esm/saved_id_list.js.map +1 -0
- package/package.json +69 -0
- package/src/id.ts +75 -0
- package/src/id_list.ts +471 -0
- package/src/index.ts +3 -0
- package/src/saved_id_list.ts +13 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright © 2025 Matthew Weidner
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# articulated
|
|
2
|
+
|
|
3
|
+
A TypeScript library for managing stable element identifiers in mutable lists, perfect for collaborative editing and other applications where elements need persistent identities despite insertions and deletions.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Stable identifiers**: Elements keep their identity even as their indices change
|
|
8
|
+
- **Efficient storage**: Optimized compression for sequential IDs
|
|
9
|
+
- **Collaborative-ready**: Supports concurrent operations from multiple sources
|
|
10
|
+
- **Tombstone support**: Deleted elements remain addressable
|
|
11
|
+
- **TypeScript-first**: Full type safety and excellent IDE integration
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install --save articulated
|
|
17
|
+
# or
|
|
18
|
+
yarn add articulated
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Quick Start
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
import { IdList } from "articulated";
|
|
25
|
+
|
|
26
|
+
// Create an empty list
|
|
27
|
+
const list = new IdList();
|
|
28
|
+
|
|
29
|
+
// Insert a new element at the beginning
|
|
30
|
+
list.insertAfter(null, { bunchId: "user1", counter: 0 });
|
|
31
|
+
|
|
32
|
+
// Insert another element after the first
|
|
33
|
+
list.insertAfter(
|
|
34
|
+
{ bunchId: "user1", counter: 0 },
|
|
35
|
+
{ bunchId: "user1", counter: 1 }
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
// Delete an element (marks as deleted but keeps as known)
|
|
39
|
+
list.delete({ bunchId: "user1", counter: 0 });
|
|
40
|
+
|
|
41
|
+
// Check if elements are present/known
|
|
42
|
+
console.log(list.has({ bunchId: "user1", counter: 0 })); // false (deleted)
|
|
43
|
+
console.log(list.isKnown({ bunchId: "user1", counter: 0 })); // true (known but deleted)
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Core Concepts
|
|
47
|
+
|
|
48
|
+
### ElementId
|
|
49
|
+
|
|
50
|
+
An `ElementId` is a globally unique identifier for a list element, composed of:
|
|
51
|
+
|
|
52
|
+
- `bunchId`: A string UUID or similar globally unique ID
|
|
53
|
+
- `counter`: A numeric value to distinguish elements in the same bunch
|
|
54
|
+
|
|
55
|
+
For optimal compression, when inserting multiple elements in sequence, use the same `bunchId` with sequential `counter` values.
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
// Example of IDs that will compress well
|
|
59
|
+
const id1 = { bunchId: "abc123", counter: 0 };
|
|
60
|
+
const id2 = { bunchId: "abc123", counter: 1 };
|
|
61
|
+
const id3 = { bunchId: "abc123", counter: 2 };
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### IdList Operations
|
|
65
|
+
|
|
66
|
+
#### Basic Operations
|
|
67
|
+
|
|
68
|
+
- `insertAfter(before, newId)`: Insert after a specific element
|
|
69
|
+
- `insertBefore(after, newId)`: Insert before a specific element
|
|
70
|
+
- `delete(id)`: Mark an element as deleted (remains known)
|
|
71
|
+
- `undelete(id)`: Restore a deleted element
|
|
72
|
+
|
|
73
|
+
#### Advanced Operations
|
|
74
|
+
|
|
75
|
+
- `uninsert(id)`: Remove an element completely (no longer known)
|
|
76
|
+
- `at(index)`: Get the element ID at a specific index
|
|
77
|
+
- `indexOf(id, bias)`: Get the index of an element with optional bias for deleted elements
|
|
78
|
+
- `clone()`: Create a deep copy of the list
|
|
79
|
+
|
|
80
|
+
#### Bulk Operations
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
// Insert multiple sequential ids at once
|
|
84
|
+
list.insertAfter(null, { bunchId: "user1", counter: 0 }, 5);
|
|
85
|
+
// Inserts 5 ids with bunchId="user1" and counters 0, 1, 2, 3, 4
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Persistence
|
|
89
|
+
|
|
90
|
+
Save and restore the list state:
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
// Save list state
|
|
94
|
+
const savedState = list.save();
|
|
95
|
+
|
|
96
|
+
// Later, restore from saved state
|
|
97
|
+
const newList = new IdList();
|
|
98
|
+
newList.load(savedState);
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Use Cases
|
|
102
|
+
|
|
103
|
+
- Text editors where characters need stable identities
|
|
104
|
+
- Todo lists with collaborative editing
|
|
105
|
+
- Any list where elements' positions change but need stable identifiers
|
|
106
|
+
- Conflict-free replicated data type (CRDT) implementations
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A unique and immutable id for a list element.
|
|
3
|
+
*
|
|
4
|
+
* ElementIds are conceptually the same as UUIDs (or nanoids, etc.).
|
|
5
|
+
* However, when a single thread generates a series of ElementIds, you are
|
|
6
|
+
* allowed to optimize by generating a single UUID/nanoid/etc. and using that as the "bunchId"
|
|
7
|
+
* for a "bunch" of elements, with varying `counter`.
|
|
8
|
+
* The resulting ElementIds compress better than a set of UUIDs, but they are
|
|
9
|
+
* still globally unique, even if another thread/user/device generates ElementIds concurrently.
|
|
10
|
+
*
|
|
11
|
+
* For example, if a user types a sentence from left to right, you may generate a
|
|
12
|
+
* single `bunchId` and assign their characters the sequential ElementIds
|
|
13
|
+
* `{ bunchId, counter: 0 }, { bunchId, counter: 1 }, { bunchId, counter: 2 }, ...`.
|
|
14
|
+
* An IdList will store all of these as a single object instead of
|
|
15
|
+
* one object per ElementId.
|
|
16
|
+
*/
|
|
17
|
+
export interface ElementId {
|
|
18
|
+
/**
|
|
19
|
+
* A UUID or similar globally unique ID.
|
|
20
|
+
*
|
|
21
|
+
* You must choose this so that the resulting ElementId is globally unique,
|
|
22
|
+
* even if another part of your application creates
|
|
23
|
+
* ElementIds concurrently (possibly on a different device).
|
|
24
|
+
*/
|
|
25
|
+
readonly bunchId: string;
|
|
26
|
+
/**
|
|
27
|
+
* An integer used to distinguish ElementIds in the same bunch.
|
|
28
|
+
*
|
|
29
|
+
* Typically, you will assign sequential counters 0, 1, 2, ... to list elements
|
|
30
|
+
* that are initially inserted in a left-to-right order.
|
|
31
|
+
* IdList is optimized for this case, but it is not mandatory.
|
|
32
|
+
* In particular, it is okay if future edits cause the sequential ids to be
|
|
33
|
+
* separated, partially deleted, or even reordered.
|
|
34
|
+
*
|
|
35
|
+
* Negative integers are supported by IdList (e.g., for optimized right-to-left insertions),
|
|
36
|
+
* though you may choose to avoid these in your application, to make serialization easier.
|
|
37
|
+
*/
|
|
38
|
+
readonly counter: number;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Equals function for ElementIds.
|
|
42
|
+
*/
|
|
43
|
+
export declare function equalsId(a: ElementId, b: ElementId): boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Expands a "compressed" sequence of ElementIds that have the same bunchId but
|
|
46
|
+
* sequentially increasing counters, starting at `startId.counter`.
|
|
47
|
+
*
|
|
48
|
+
* For example,
|
|
49
|
+
* ```ts
|
|
50
|
+
* expandIds({ bunchId: "foo", counter: 7 }, 3)
|
|
51
|
+
* ```
|
|
52
|
+
* returns
|
|
53
|
+
* ```ts
|
|
54
|
+
* [
|
|
55
|
+
* { bunchId: "foo", counter: 7 },
|
|
56
|
+
* { bunchId: "foo", counter: 8 },
|
|
57
|
+
* { bunchId: "foo", counter: 9 }
|
|
58
|
+
* ]
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
export declare function expandIds(startId: ElementId, count: number): ElementId[];
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.expandIds = exports.equalsId = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Equals function for ElementIds.
|
|
6
|
+
*/
|
|
7
|
+
function equalsId(a, b) {
|
|
8
|
+
return a.counter === b.counter && a.bunchId === b.bunchId;
|
|
9
|
+
}
|
|
10
|
+
exports.equalsId = equalsId;
|
|
11
|
+
/**
|
|
12
|
+
* Expands a "compressed" sequence of ElementIds that have the same bunchId but
|
|
13
|
+
* sequentially increasing counters, starting at `startId.counter`.
|
|
14
|
+
*
|
|
15
|
+
* For example,
|
|
16
|
+
* ```ts
|
|
17
|
+
* expandIds({ bunchId: "foo", counter: 7 }, 3)
|
|
18
|
+
* ```
|
|
19
|
+
* returns
|
|
20
|
+
* ```ts
|
|
21
|
+
* [
|
|
22
|
+
* { bunchId: "foo", counter: 7 },
|
|
23
|
+
* { bunchId: "foo", counter: 8 },
|
|
24
|
+
* { bunchId: "foo", counter: 9 }
|
|
25
|
+
* ]
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
function expandIds(startId, count) {
|
|
29
|
+
if (!(Number.isSafeInteger(count) && count >= 0)) {
|
|
30
|
+
throw new Error(`Invalid count: ${count}`);
|
|
31
|
+
}
|
|
32
|
+
const ans = [];
|
|
33
|
+
for (let i = 0; i < count; i++) {
|
|
34
|
+
ans.push({ bunchId: startId.bunchId, counter: startId.counter + i });
|
|
35
|
+
}
|
|
36
|
+
return ans;
|
|
37
|
+
}
|
|
38
|
+
exports.expandIds = expandIds;
|
|
39
|
+
//# sourceMappingURL=id.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"id.js","sourceRoot":"","sources":["../../src/id.ts"],"names":[],"mappings":";;;AAwCA;;GAEG;AACH,SAAgB,QAAQ,CAAC,CAAY,EAAE,CAAY;IACjD,OAAO,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,OAAO,CAAC;AAC5D,CAAC;AAFD,4BAEC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,SAAgB,SAAS,CAAC,OAAkB,EAAE,KAAa;IACzD,IAAI,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,EAAE,CAAC;QACjD,MAAM,IAAI,KAAK,CAAC,kBAAkB,KAAK,EAAE,CAAC,CAAC;IAC7C,CAAC;IAED,MAAM,GAAG,GAAgB,EAAE,CAAC;IAC5B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;QAC/B,GAAG,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,GAAG,CAAC,EAAE,CAAC,CAAC;IACvE,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAVD,8BAUC"}
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import { ElementId } from "./id";
|
|
2
|
+
import { SavedIdList } from "./saved_id_list";
|
|
3
|
+
interface ListElement {
|
|
4
|
+
id: ElementId;
|
|
5
|
+
isDeleted: boolean;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* A list of ElementIds.
|
|
9
|
+
*
|
|
10
|
+
* An IdList helps you assign a unique immutable id to each element of a list, such
|
|
11
|
+
* as a todo-list or a text document (= list of characters). That way, you can keep track
|
|
12
|
+
* of those elements even as their (array) indices change due to insert/delete operations
|
|
13
|
+
* earlier in the list.
|
|
14
|
+
*
|
|
15
|
+
* Any id that has been inserted into an IdList remains **known** to that list indefinitely,
|
|
16
|
+
* allowing you to reference it in insertAfter/insertBefore operations. Calling {@link delete}
|
|
17
|
+
* merely marks an id as deleted (not present); it remains in memory as a "tombstone".
|
|
18
|
+
* This is useful in collaborative settings, since another user might instruct you to
|
|
19
|
+
* call `insertAfter(before, newId)` when you have already deleted `before` locally.
|
|
20
|
+
* If that is not a concern and you truly want to make an id no longer known, instead
|
|
21
|
+
* call {@link uninsert}.
|
|
22
|
+
*
|
|
23
|
+
* See {@link ElementId} for advice on generating ElementIds. IdList is optimized for
|
|
24
|
+
* the case where sequential ElementIds often have the same bunchId and sequential counters.
|
|
25
|
+
* However, you are not required to order ids in this way - it is okay if future edits
|
|
26
|
+
* cause such ids to be separated, partially deleted, or even reordered.
|
|
27
|
+
*/
|
|
28
|
+
export declare class IdList {
|
|
29
|
+
private readonly state;
|
|
30
|
+
private _length;
|
|
31
|
+
/**
|
|
32
|
+
* Constructs an empty list.
|
|
33
|
+
*
|
|
34
|
+
* To begin with a non-empty list, use {@link IdList.from} or {@link IdList.fromIds}.
|
|
35
|
+
*/
|
|
36
|
+
constructor();
|
|
37
|
+
/**
|
|
38
|
+
* Constructs a list with the given known ids and their isDeleted status, in list order.
|
|
39
|
+
*/
|
|
40
|
+
static from(state: Iterable<{
|
|
41
|
+
id: ElementId;
|
|
42
|
+
isDeleted: boolean;
|
|
43
|
+
}>): IdList;
|
|
44
|
+
/**
|
|
45
|
+
* Constructs a list with the given present ids.
|
|
46
|
+
*
|
|
47
|
+
* Typically, you instead want {@link IdList.from}, which allows you to also
|
|
48
|
+
* specify known-but-deleted ids. That way, you can reference the known-but-deleted ids
|
|
49
|
+
* in future insertAfter/insertBefore operations.
|
|
50
|
+
*/
|
|
51
|
+
static fromIds(ids: Iterable<ElementId>): IdList;
|
|
52
|
+
/**
|
|
53
|
+
* Inserts `newId` immediately after the given id (`before`), which may be deleted.
|
|
54
|
+
* All ids to the right of `before` are shifted one index to the right, in the manner
|
|
55
|
+
* of [Array.splice](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice).
|
|
56
|
+
*
|
|
57
|
+
* Use `before = null` to insert at the beginning of the list, to the left of all
|
|
58
|
+
* known ids.
|
|
59
|
+
*
|
|
60
|
+
* @param count Provide this to bulk-insert `count` ids from left-to-right,
|
|
61
|
+
* starting with newId and proceeding with the same bunchId and sequential counters.
|
|
62
|
+
* @throws If `before` is not known.
|
|
63
|
+
* @throws If `newId` is already known.
|
|
64
|
+
*/
|
|
65
|
+
insertAfter(before: ElementId | null, newId: ElementId, count?: number): void;
|
|
66
|
+
/**
|
|
67
|
+
* Inserts `newId` immediately before the given id (`after`), which may be deleted.
|
|
68
|
+
* All ids to the right of `after`, plus `after` itself, are shifted one index to the right, in the manner
|
|
69
|
+
* of [Array.splice](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice).
|
|
70
|
+
*
|
|
71
|
+
* Use `after = null` to insert at the end of the list, to the right of all known ids.
|
|
72
|
+
*
|
|
73
|
+
* @param count Provide this to bulk-insert `count` ids from left-to-right,
|
|
74
|
+
* starting with newId and proceeding with the same bunchId and sequential counters.
|
|
75
|
+
* __Note__: Although the new ids are inserted to the left of `after`, they are still
|
|
76
|
+
* inserted in left-to-right order relative to each other.
|
|
77
|
+
* @throws If `after` is not known.
|
|
78
|
+
* @throws If `newId` is already known.
|
|
79
|
+
*/
|
|
80
|
+
insertBefore(after: ElementId | null, newId: ElementId, count?: number): void;
|
|
81
|
+
/**
|
|
82
|
+
* Un-inserts `id` from the list, making it no longer known or present in this list.
|
|
83
|
+
*
|
|
84
|
+
* Typically, you instead want to call {@link delete}, which marks `id` as deleted while
|
|
85
|
+
* it remains known. That way, you can reference `id` in future insertAfter/insertBefore
|
|
86
|
+
* operations, including ones sent concurrently by other devices.
|
|
87
|
+
*
|
|
88
|
+
* If `id` is already not known, this method does nothing.
|
|
89
|
+
*/
|
|
90
|
+
uninsert(id: ElementId): void;
|
|
91
|
+
/**
|
|
92
|
+
* Marks `id` as deleted from this list. The id remains known (a "tombstone").
|
|
93
|
+
*
|
|
94
|
+
* Because `id` is still known, you can reference it in future insertAfter/insertBefore
|
|
95
|
+
* operations, including ones sent concurrently by other devices.
|
|
96
|
+
* However, it does occupy space in memory (compressed in common cases).
|
|
97
|
+
*
|
|
98
|
+
* For an exact inverse to `insertAfter(-, id)` or `insertBefore(-, id)`
|
|
99
|
+
* that makes `id` no longer known, see {@link uninsert}.
|
|
100
|
+
*
|
|
101
|
+
* If `id` is already deleted or not known, this method does nothing.
|
|
102
|
+
*/
|
|
103
|
+
delete(id: ElementId): void;
|
|
104
|
+
/**
|
|
105
|
+
* Un-marks `id` as deleted from this list, making it present again.
|
|
106
|
+
* This is an exact inverse to {@link delete}.
|
|
107
|
+
*
|
|
108
|
+
* If `id` is already present, this method does nothing.
|
|
109
|
+
*
|
|
110
|
+
* @throws If `id` is not known.
|
|
111
|
+
*/
|
|
112
|
+
undelete(id: ElementId): void;
|
|
113
|
+
/**
|
|
114
|
+
* Returns whether `id` is present in the list, i.e., it is known and not deleted.
|
|
115
|
+
*
|
|
116
|
+
* If `id` is not known, false is returned.
|
|
117
|
+
*
|
|
118
|
+
* Compare to {@link isKnown}.
|
|
119
|
+
*/
|
|
120
|
+
has(id: ElementId): boolean;
|
|
121
|
+
/**
|
|
122
|
+
* Returns whether id is known to this list.
|
|
123
|
+
*
|
|
124
|
+
* Compare to {@link has}.
|
|
125
|
+
*/
|
|
126
|
+
isKnown(id: ElementId): boolean;
|
|
127
|
+
/**
|
|
128
|
+
* Returns the id at the given index in the list.
|
|
129
|
+
*
|
|
130
|
+
* @throws If index is out of bounds.
|
|
131
|
+
*/
|
|
132
|
+
at(index: number): ElementId;
|
|
133
|
+
/**
|
|
134
|
+
* Returns the index of `id` in the list.
|
|
135
|
+
*
|
|
136
|
+
* If `id` is known but deleted, the bias specifies what to return:
|
|
137
|
+
* - "none": -1.
|
|
138
|
+
* - "left": The index immediately to the left of `id`, possibly -1.
|
|
139
|
+
* - "right": The index immediately to the right of `id`, possibly `this.length`.
|
|
140
|
+
* Equivalently, the index where `id` would be if present.
|
|
141
|
+
*
|
|
142
|
+
* @throws If `id` is not known.
|
|
143
|
+
*/
|
|
144
|
+
indexOf(id: ElementId, bias?: "none" | "left" | "right"): number;
|
|
145
|
+
/**
|
|
146
|
+
* The length of the list.
|
|
147
|
+
*/
|
|
148
|
+
get length(): number;
|
|
149
|
+
/**
|
|
150
|
+
* Iterates over all present ids in the list.
|
|
151
|
+
*/
|
|
152
|
+
[Symbol.iterator](): IterableIterator<ElementId>;
|
|
153
|
+
/**
|
|
154
|
+
* Iterates over all present ids in the list.
|
|
155
|
+
*/
|
|
156
|
+
values(): IterableIterator<ElementId>;
|
|
157
|
+
/**
|
|
158
|
+
* Iterates over all __known__ ids in the list, indicating which are deleted.
|
|
159
|
+
*/
|
|
160
|
+
valuesWithDeleted(): IterableIterator<{
|
|
161
|
+
id: ElementId;
|
|
162
|
+
isDeleted: boolean;
|
|
163
|
+
}>;
|
|
164
|
+
/**
|
|
165
|
+
* Returns an independent copy of this list, including known but deleted ids.
|
|
166
|
+
*/
|
|
167
|
+
clone(): IdList;
|
|
168
|
+
private _knownIds?;
|
|
169
|
+
/**
|
|
170
|
+
* A live-updating view of this list that treats all known ids as present.
|
|
171
|
+
* That is, it ignores isDeleted status when computing list indices or iterating.
|
|
172
|
+
*/
|
|
173
|
+
get knownIds(): KnownIdView;
|
|
174
|
+
/**
|
|
175
|
+
* Returns a compact JSON representation of this list's internal state.
|
|
176
|
+
* Load with {@link load}.
|
|
177
|
+
*
|
|
178
|
+
* See {@link SavedIdList} for a description of the save format.
|
|
179
|
+
*/
|
|
180
|
+
save(): SavedIdList;
|
|
181
|
+
/**
|
|
182
|
+
* Loads a saved state returned by {@link save}, __overwriting__ the current state of this list.
|
|
183
|
+
*/
|
|
184
|
+
load(savedState: SavedIdList): void;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* A live-updating view of an IdList that treats all known ids as present.
|
|
188
|
+
* That is, this class ignores the underlying list's isDeleted status when computing list indices.
|
|
189
|
+
*
|
|
190
|
+
* To mutate, call methods on the original IdList (`this.list`).
|
|
191
|
+
*/
|
|
192
|
+
export declare class KnownIdView {
|
|
193
|
+
readonly list: IdList;
|
|
194
|
+
private readonly state;
|
|
195
|
+
/**
|
|
196
|
+
* Internal use only. Use {@link IdList.knownIds} instead.
|
|
197
|
+
*/
|
|
198
|
+
constructor(list: IdList, state: ListElement[]);
|
|
199
|
+
/**
|
|
200
|
+
* Returns the id at the given index in this view.
|
|
201
|
+
*
|
|
202
|
+
* Equivalently, returns the index-th known id in `this.list`.
|
|
203
|
+
*
|
|
204
|
+
* @throws If index is out of bounds.
|
|
205
|
+
*/
|
|
206
|
+
at(index: number): ElementId;
|
|
207
|
+
/**
|
|
208
|
+
* Returns the index of `id` in this view, or -1 if it is not known.
|
|
209
|
+
*/
|
|
210
|
+
indexOf(id: ElementId): number;
|
|
211
|
+
/**
|
|
212
|
+
* The length of this view.
|
|
213
|
+
*
|
|
214
|
+
* Equivalently, the number of known ids in `this.list`.
|
|
215
|
+
*/
|
|
216
|
+
get length(): number;
|
|
217
|
+
/**
|
|
218
|
+
* Iterates over all ids in this view, i.e., all known ids in `this.list`.
|
|
219
|
+
*/
|
|
220
|
+
[Symbol.iterator](): IterableIterator<ElementId>;
|
|
221
|
+
/**
|
|
222
|
+
* Iterates over all ids in this view, i.e., all known ids in `this.list`.
|
|
223
|
+
*/
|
|
224
|
+
values(): IterableIterator<ElementId>;
|
|
225
|
+
}
|
|
226
|
+
export {};
|