@liveblocks/client 0.15.0-alpha.3 → 0.15.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/README.md +5 -10
  2. package/lib/esm/index.js +2991 -5
  3. package/lib/esm/index.mjs +2991 -0
  4. package/lib/esm/internal.js +149 -0
  5. package/lib/esm/internal.mjs +149 -0
  6. package/lib/{esm/types.d.ts → index.d.ts} +253 -61
  7. package/lib/index.js +4237 -0
  8. package/lib/{esm/live.d.ts → internal.d.ts} +46 -34
  9. package/lib/internal.js +193 -0
  10. package/package.json +32 -10
  11. package/lib/cjs/AbstractCrdt.d.ts +0 -68
  12. package/lib/cjs/AbstractCrdt.js +0 -95
  13. package/lib/cjs/LiveList.d.ts +0 -144
  14. package/lib/cjs/LiveList.js +0 -530
  15. package/lib/cjs/LiveMap.d.ts +0 -91
  16. package/lib/cjs/LiveMap.js +0 -325
  17. package/lib/cjs/LiveObject.d.ts +0 -80
  18. package/lib/cjs/LiveObject.js +0 -485
  19. package/lib/cjs/LiveRegister.d.ts +0 -29
  20. package/lib/cjs/LiveRegister.js +0 -88
  21. package/lib/cjs/client.d.ts +0 -27
  22. package/lib/cjs/client.js +0 -123
  23. package/lib/cjs/immutable.d.ts +0 -9
  24. package/lib/cjs/immutable.js +0 -299
  25. package/lib/cjs/index.d.ts +0 -6
  26. package/lib/cjs/index.js +0 -18
  27. package/lib/cjs/live.d.ts +0 -181
  28. package/lib/cjs/live.js +0 -49
  29. package/lib/cjs/position.d.ts +0 -6
  30. package/lib/cjs/position.js +0 -113
  31. package/lib/cjs/room.d.ts +0 -159
  32. package/lib/cjs/room.js +0 -1129
  33. package/lib/cjs/types.d.ts +0 -502
  34. package/lib/cjs/types.js +0 -2
  35. package/lib/cjs/utils.d.ts +0 -15
  36. package/lib/cjs/utils.js +0 -225
  37. package/lib/esm/AbstractCrdt.d.ts +0 -68
  38. package/lib/esm/AbstractCrdt.js +0 -91
  39. package/lib/esm/LiveList.d.ts +0 -144
  40. package/lib/esm/LiveList.js +0 -526
  41. package/lib/esm/LiveMap.d.ts +0 -91
  42. package/lib/esm/LiveMap.js +0 -321
  43. package/lib/esm/LiveObject.d.ts +0 -80
  44. package/lib/esm/LiveObject.js +0 -481
  45. package/lib/esm/LiveRegister.d.ts +0 -29
  46. package/lib/esm/LiveRegister.js +0 -84
  47. package/lib/esm/client.d.ts +0 -27
  48. package/lib/esm/client.js +0 -119
  49. package/lib/esm/immutable.d.ts +0 -9
  50. package/lib/esm/immutable.js +0 -290
  51. package/lib/esm/index.d.ts +0 -6
  52. package/lib/esm/live.js +0 -46
  53. package/lib/esm/position.d.ts +0 -6
  54. package/lib/esm/position.js +0 -106
  55. package/lib/esm/room.d.ts +0 -159
  56. package/lib/esm/room.js +0 -1123
  57. package/lib/esm/types.js +0 -1
  58. package/lib/esm/utils.d.ts +0 -15
  59. package/lib/esm/utils.js +0 -213
package/lib/esm/client.js DELETED
@@ -1,119 +0,0 @@
1
- import { createRoom } from "./room";
2
- /**
3
- * Create a client that will be responsible to communicate with liveblocks servers.
4
- *
5
- * @example
6
- * const client = createClient({
7
- * authEndpoint: "/api/auth"
8
- * });
9
- *
10
- * // It's also possible to use a function to call your authentication endpoint.
11
- * // Useful to add additional headers or use an API wrapper (like Firebase functions)
12
- * const client = createClient({
13
- * authEndpoint: async (room) => {
14
- * const response = await fetch("/api/auth", {
15
- * method: "POST",
16
- * headers: {
17
- * Authentication: "token",
18
- * "Content-Type": "application/json"
19
- * },
20
- * body: JSON.stringify({ room })
21
- * });
22
- *
23
- * return await response.json();
24
- * }
25
- * });
26
- */
27
- export function createClient(options) {
28
- const clientOptions = options;
29
- const throttleDelay = getThrottleDelayFromOptions(options);
30
- const rooms = new Map();
31
- function getRoom(roomId) {
32
- const internalRoom = rooms.get(roomId);
33
- return internalRoom ? internalRoom.room : null;
34
- }
35
- function enter(roomId, options = {}) {
36
- let internalRoom = rooms.get(roomId);
37
- if (internalRoom) {
38
- return internalRoom.room;
39
- }
40
- internalRoom = createRoom({
41
- defaultPresence: options.defaultPresence,
42
- defaultStorageRoot: options.defaultStorageRoot,
43
- }, {
44
- room: roomId,
45
- throttleDelay,
46
- WebSocketPolyfill: clientOptions.WebSocketPolyfill,
47
- fetchPolyfill: clientOptions.fetchPolyfill,
48
- liveblocksServer: clientOptions.liveblocksServer || "wss://liveblocks.net/v5",
49
- authentication: prepareAuthentication(clientOptions),
50
- });
51
- rooms.set(roomId, internalRoom);
52
- if (!options.DO_NOT_USE_withoutConnecting) {
53
- internalRoom.connect();
54
- }
55
- return internalRoom.room;
56
- }
57
- function leave(roomId) {
58
- let room = rooms.get(roomId);
59
- if (room) {
60
- room.disconnect();
61
- rooms.delete(roomId);
62
- }
63
- }
64
- if (typeof window !== "undefined") {
65
- // TODO: Expose a way to clear these
66
- window.addEventListener("online", () => {
67
- for (const [, room] of rooms) {
68
- room.onNavigatorOnline();
69
- }
70
- });
71
- }
72
- if (typeof document !== "undefined") {
73
- document.addEventListener("visibilitychange", () => {
74
- for (const [, room] of rooms) {
75
- room.onVisibilityChange(document.visibilityState);
76
- }
77
- });
78
- }
79
- return {
80
- getRoom,
81
- enter,
82
- leave,
83
- };
84
- }
85
- function getThrottleDelayFromOptions(options) {
86
- if (options.throttle === undefined) {
87
- return 100;
88
- }
89
- if (typeof options.throttle !== "number" ||
90
- options.throttle < 80 ||
91
- options.throttle > 1000) {
92
- throw new Error("throttle should be a number between 80 and 1000.");
93
- }
94
- return options.throttle;
95
- }
96
- function prepareAuthentication(clientOptions) {
97
- // TODO: throw descriptive errors for invalid options
98
- if (typeof clientOptions.publicApiKey === "string") {
99
- return {
100
- type: "public",
101
- publicApiKey: clientOptions.publicApiKey,
102
- url: clientOptions.publicAuthorizeEndpoint ||
103
- "https://liveblocks.io/api/public/authorize",
104
- };
105
- }
106
- else if (typeof clientOptions.authEndpoint === "string") {
107
- return {
108
- type: "private",
109
- url: clientOptions.authEndpoint,
110
- };
111
- }
112
- else if (typeof clientOptions.authEndpoint === "function") {
113
- return {
114
- type: "custom",
115
- callback: clientOptions.authEndpoint,
116
- };
117
- }
118
- throw new Error("Invalid Liveblocks client options. For more information: https://liveblocks.io/docs/api-reference/liveblocks-client#createClient");
119
- }
@@ -1,9 +0,0 @@
1
- import { LiveList } from "./LiveList";
2
- import { LiveObject } from "./LiveObject";
3
- import { StorageUpdate } from "./types";
4
- export declare function liveObjectToJson(liveObject: LiveObject<any>): any;
5
- export declare function liveNodeToJson(value: any): any;
6
- export declare function patchLiveList<T>(liveList: LiveList<T>, prev: Array<T>, next: Array<T>): void;
7
- export declare function patchLiveObjectKey<T>(liveObject: LiveObject<T>, key: keyof T, prev: any, next: any): void;
8
- export declare function patchLiveObject<T extends Record<string, any>>(root: LiveObject<T>, prev: T, next: T): void;
9
- export declare function patchImmutableObject<T>(state: T, updates: StorageUpdate[]): T;
@@ -1,290 +0,0 @@
1
- import { LiveList } from "./LiveList";
2
- import { LiveMap } from "./LiveMap";
3
- import { LiveObject } from "./LiveObject";
4
- import { LiveRegister } from "./LiveRegister";
5
- import { findNonSerializableValue } from "./utils";
6
- export function liveObjectToJson(liveObject) {
7
- const result = {};
8
- const obj = liveObject.toObject();
9
- for (const key in obj) {
10
- result[key] = liveNodeToJson(obj[key]);
11
- }
12
- return result;
13
- }
14
- function liveMapToJson(map) {
15
- const result = {};
16
- const obj = Object.fromEntries(map);
17
- for (const key in obj) {
18
- result[key] = liveNodeToJson(obj[key]);
19
- }
20
- return result;
21
- }
22
- function liveListToJson(value) {
23
- return value.toArray().map(liveNodeToJson);
24
- }
25
- export function liveNodeToJson(value) {
26
- if (value instanceof LiveObject) {
27
- return liveObjectToJson(value);
28
- }
29
- else if (value instanceof LiveList) {
30
- return liveListToJson(value);
31
- }
32
- else if (value instanceof LiveMap) {
33
- return liveMapToJson(value);
34
- }
35
- else if (value instanceof LiveRegister) {
36
- return value.data;
37
- }
38
- return value;
39
- }
40
- function isPlainObject(obj) {
41
- return Object.prototype.toString.call(obj) === "[object Object]";
42
- }
43
- function anyToCrdt(obj) {
44
- if (obj == null) {
45
- return obj;
46
- }
47
- if (Array.isArray(obj)) {
48
- return new LiveList(obj.map(anyToCrdt));
49
- }
50
- if (isPlainObject(obj)) {
51
- const init = {};
52
- for (const key in obj) {
53
- init[key] = anyToCrdt(obj[key]);
54
- }
55
- return new LiveObject(init);
56
- }
57
- return obj;
58
- }
59
- export function patchLiveList(liveList, prev, next) {
60
- let i = 0;
61
- let prevEnd = prev.length - 1;
62
- let nextEnd = next.length - 1;
63
- let prevNode = prev[0];
64
- let nextNode = next[0];
65
- /**
66
- * For A,B,C => A,B,C,D
67
- * i = 3, prevEnd = 2, nextEnd = 3
68
- *
69
- * For A,B,C => B,C
70
- * i = 2, prevEnd = 2, nextEnd = 1
71
- *
72
- * For B,C => A,B,C
73
- * i = 0, pre
74
- */
75
- outer: {
76
- while (prevNode === nextNode) {
77
- ++i;
78
- if (i > prevEnd || i > nextEnd) {
79
- break outer;
80
- }
81
- prevNode = prev[i];
82
- nextNode = next[i];
83
- }
84
- prevNode = prev[prevEnd];
85
- nextNode = next[nextEnd];
86
- while (prevNode === nextNode) {
87
- prevEnd--;
88
- nextEnd--;
89
- if (i > prevEnd || i > nextEnd) {
90
- break outer;
91
- }
92
- prevNode = prev[prevEnd];
93
- nextNode = next[nextEnd];
94
- }
95
- }
96
- if (i > prevEnd) {
97
- if (i <= nextEnd) {
98
- while (i <= nextEnd) {
99
- liveList.insert(anyToCrdt(next[i]), i);
100
- i++;
101
- }
102
- }
103
- }
104
- else if (i > nextEnd) {
105
- let localI = i;
106
- while (localI <= prevEnd) {
107
- liveList.delete(i);
108
- localI++;
109
- }
110
- }
111
- else {
112
- while (i <= prevEnd && i <= nextEnd) {
113
- prevNode = prev[i];
114
- nextNode = next[i];
115
- const liveListNode = liveList.get(i);
116
- if (liveListNode instanceof LiveObject &&
117
- isPlainObject(prevNode) &&
118
- isPlainObject(nextNode)) {
119
- patchLiveObject(liveListNode, prevNode, nextNode);
120
- }
121
- else {
122
- liveList.delete(i);
123
- liveList.insert(anyToCrdt(nextNode), i);
124
- }
125
- i++;
126
- }
127
- while (i <= nextEnd) {
128
- liveList.insert(anyToCrdt(next[i]), i);
129
- i++;
130
- }
131
- while (i <= prevEnd) {
132
- liveList.delete(i);
133
- i++;
134
- }
135
- }
136
- }
137
- export function patchLiveObjectKey(liveObject, key, prev, next) {
138
- if (process.env.NODE_ENV !== "production") {
139
- const nonSerializableValue = findNonSerializableValue(next);
140
- if (nonSerializableValue) {
141
- console.error(`New state path: '${nonSerializableValue.path}' value: '${nonSerializableValue.value}' is not serializable.\nOnly serializable value can be synced with Liveblocks.`);
142
- return;
143
- }
144
- }
145
- const value = liveObject.get(key);
146
- if (next === undefined) {
147
- liveObject.delete(key);
148
- }
149
- else if (value === undefined) {
150
- liveObject.set(key, anyToCrdt(next));
151
- }
152
- else if (prev === next) {
153
- return;
154
- }
155
- else if (value instanceof LiveList &&
156
- Array.isArray(prev) &&
157
- Array.isArray(next)) {
158
- patchLiveList(value, prev, next);
159
- }
160
- else if (value instanceof LiveObject &&
161
- isPlainObject(prev) &&
162
- isPlainObject(next)) {
163
- patchLiveObject(value, prev, next);
164
- }
165
- else {
166
- liveObject.set(key, anyToCrdt(next));
167
- }
168
- }
169
- export function patchLiveObject(root, prev, next) {
170
- const updates = {};
171
- for (const key in next) {
172
- patchLiveObjectKey(root, key, prev[key], next[key]);
173
- }
174
- for (const key in prev) {
175
- if (next[key] === undefined) {
176
- root.delete(key);
177
- }
178
- }
179
- if (Object.keys(updates).length > 0) {
180
- root.update(updates);
181
- }
182
- }
183
- function getParentsPath(node) {
184
- const path = [];
185
- while (node._parentKey != null && node._parent != null) {
186
- if (node._parent instanceof LiveList) {
187
- path.push(node._parent._indexOfPosition(node._parentKey));
188
- }
189
- else {
190
- path.push(node._parentKey);
191
- }
192
- node = node._parent;
193
- }
194
- return path;
195
- }
196
- export function patchImmutableObject(state, updates) {
197
- return updates.reduce((state, update) => patchImmutableObjectWithUpdate(state, update), state);
198
- }
199
- function patchImmutableObjectWithUpdate(state, update) {
200
- const path = getParentsPath(update.node);
201
- return patchImmutableNode(state, path, update);
202
- }
203
- function patchImmutableNode(state, path, update) {
204
- var _a, _b, _c, _d;
205
- const pathItem = path.pop();
206
- if (pathItem === undefined) {
207
- switch (update.type) {
208
- case "LiveObject": {
209
- if (typeof state !== "object") {
210
- throw new Error("Internal: received update on LiveObject but state was not an object");
211
- }
212
- let newState = Object.assign({}, state);
213
- for (const key in update.updates) {
214
- if (((_a = update.updates[key]) === null || _a === void 0 ? void 0 : _a.type) === "update") {
215
- newState[key] = liveNodeToJson(update.node.get(key));
216
- }
217
- else if (((_b = update.updates[key]) === null || _b === void 0 ? void 0 : _b.type) === "delete") {
218
- delete newState[key];
219
- }
220
- }
221
- return newState;
222
- }
223
- case "LiveList": {
224
- if (Array.isArray(state) === false) {
225
- throw new Error("Internal: received update on LiveList but state was not an array");
226
- }
227
- let newState = state.map((x) => x);
228
- for (const listUpdate of update.updates) {
229
- if (listUpdate.type === "insert") {
230
- if (listUpdate.index === newState.length) {
231
- newState.push(liveNodeToJson(listUpdate.item));
232
- }
233
- else {
234
- newState = [
235
- ...newState.slice(0, listUpdate.index),
236
- liveNodeToJson(listUpdate.item),
237
- ...newState.slice(listUpdate.index),
238
- ];
239
- }
240
- }
241
- else if (listUpdate.type === "delete") {
242
- newState.splice(listUpdate.index, 1);
243
- }
244
- else if (listUpdate.type === "move") {
245
- if (listUpdate.previousIndex > listUpdate.index) {
246
- newState = [
247
- ...newState.slice(0, listUpdate.index),
248
- liveNodeToJson(listUpdate.item),
249
- ...newState.slice(listUpdate.index, listUpdate.previousIndex),
250
- ...newState.slice(listUpdate.previousIndex + 1),
251
- ];
252
- }
253
- else {
254
- newState = [
255
- ...newState.slice(0, listUpdate.previousIndex),
256
- ...newState.slice(listUpdate.previousIndex + 1, listUpdate.index + 1),
257
- liveNodeToJson(listUpdate.item),
258
- ...newState.slice(listUpdate.index + 1),
259
- ];
260
- }
261
- }
262
- }
263
- return newState;
264
- }
265
- case "LiveMap": {
266
- if (typeof state !== "object") {
267
- throw new Error("Internal: received update on LiveMap but state was not an object");
268
- }
269
- let newState = Object.assign({}, state);
270
- for (const key in update.updates) {
271
- if (((_c = update.updates[key]) === null || _c === void 0 ? void 0 : _c.type) === "update") {
272
- newState[key] = liveNodeToJson(update.node.get(key));
273
- }
274
- else if (((_d = update.updates[key]) === null || _d === void 0 ? void 0 : _d.type) === "delete") {
275
- delete newState[key];
276
- }
277
- }
278
- return newState;
279
- }
280
- }
281
- }
282
- if (Array.isArray(state)) {
283
- const newArray = [...state];
284
- newArray[pathItem] = patchImmutableNode(state[pathItem], path, update);
285
- return newArray;
286
- }
287
- else {
288
- return Object.assign(Object.assign({}, state), { [pathItem]: patchImmutableNode(state[pathItem], path, update) });
289
- }
290
- }
@@ -1,6 +0,0 @@
1
- export { LiveObject } from "./LiveObject";
2
- export { LiveMap } from "./LiveMap";
3
- export { LiveList } from "./LiveList";
4
- export type { Others, Presence, Room, Client, User, BroadcastOptions, } from "./types";
5
- export { createClient } from "./client";
6
- export { liveObjectToJson, liveNodeToJson, patchLiveList, patchImmutableObject, patchLiveObject, patchLiveObjectKey, } from "./immutable";
package/lib/esm/live.js DELETED
@@ -1,46 +0,0 @@
1
- export var ServerMessageType;
2
- (function (ServerMessageType) {
3
- ServerMessageType[ServerMessageType["UpdatePresence"] = 100] = "UpdatePresence";
4
- ServerMessageType[ServerMessageType["UserJoined"] = 101] = "UserJoined";
5
- ServerMessageType[ServerMessageType["UserLeft"] = 102] = "UserLeft";
6
- ServerMessageType[ServerMessageType["Event"] = 103] = "Event";
7
- ServerMessageType[ServerMessageType["RoomState"] = 104] = "RoomState";
8
- ServerMessageType[ServerMessageType["InitialStorageState"] = 200] = "InitialStorageState";
9
- ServerMessageType[ServerMessageType["UpdateStorage"] = 201] = "UpdateStorage";
10
- })(ServerMessageType || (ServerMessageType = {}));
11
- export var ClientMessageType;
12
- (function (ClientMessageType) {
13
- ClientMessageType[ClientMessageType["UpdatePresence"] = 100] = "UpdatePresence";
14
- ClientMessageType[ClientMessageType["ClientEvent"] = 103] = "ClientEvent";
15
- ClientMessageType[ClientMessageType["FetchStorage"] = 200] = "FetchStorage";
16
- ClientMessageType[ClientMessageType["UpdateStorage"] = 201] = "UpdateStorage";
17
- })(ClientMessageType || (ClientMessageType = {}));
18
- export var CrdtType;
19
- (function (CrdtType) {
20
- CrdtType[CrdtType["Object"] = 0] = "Object";
21
- CrdtType[CrdtType["List"] = 1] = "List";
22
- CrdtType[CrdtType["Map"] = 2] = "Map";
23
- CrdtType[CrdtType["Register"] = 3] = "Register";
24
- })(CrdtType || (CrdtType = {}));
25
- export var OpType;
26
- (function (OpType) {
27
- OpType[OpType["Init"] = 0] = "Init";
28
- OpType[OpType["SetParentKey"] = 1] = "SetParentKey";
29
- OpType[OpType["CreateList"] = 2] = "CreateList";
30
- OpType[OpType["UpdateObject"] = 3] = "UpdateObject";
31
- OpType[OpType["CreateObject"] = 4] = "CreateObject";
32
- OpType[OpType["DeleteCrdt"] = 5] = "DeleteCrdt";
33
- OpType[OpType["DeleteObjectKey"] = 6] = "DeleteObjectKey";
34
- OpType[OpType["CreateMap"] = 7] = "CreateMap";
35
- OpType[OpType["CreateRegister"] = 8] = "CreateRegister";
36
- })(OpType || (OpType = {}));
37
- export var WebsocketCloseCodes;
38
- (function (WebsocketCloseCodes) {
39
- WebsocketCloseCodes[WebsocketCloseCodes["CLOSE_ABNORMAL"] = 1006] = "CLOSE_ABNORMAL";
40
- WebsocketCloseCodes[WebsocketCloseCodes["INVALID_MESSAGE_FORMAT"] = 4000] = "INVALID_MESSAGE_FORMAT";
41
- WebsocketCloseCodes[WebsocketCloseCodes["NOT_ALLOWED"] = 4001] = "NOT_ALLOWED";
42
- WebsocketCloseCodes[WebsocketCloseCodes["MAX_NUMBER_OF_MESSAGES_PER_SECONDS"] = 4002] = "MAX_NUMBER_OF_MESSAGES_PER_SECONDS";
43
- WebsocketCloseCodes[WebsocketCloseCodes["MAX_NUMBER_OF_CONCURRENT_CONNECTIONS"] = 4003] = "MAX_NUMBER_OF_CONCURRENT_CONNECTIONS";
44
- WebsocketCloseCodes[WebsocketCloseCodes["MAX_NUMBER_OF_MESSAGES_PER_DAY_PER_APP"] = 4004] = "MAX_NUMBER_OF_MESSAGES_PER_DAY_PER_APP";
45
- WebsocketCloseCodes[WebsocketCloseCodes["MAX_NUMBER_OF_CONCURRENT_CONNECTIONS_PER_ROOM"] = 4005] = "MAX_NUMBER_OF_CONCURRENT_CONNECTIONS_PER_ROOM";
46
- })(WebsocketCloseCodes || (WebsocketCloseCodes = {}));
@@ -1,6 +0,0 @@
1
- export declare const min = 32;
2
- export declare const max = 126;
3
- export declare function makePosition(before?: string, after?: string): string;
4
- export declare function posCodes(str: string): number[];
5
- export declare function pos(codes: number[]): string;
6
- export declare function compare(posA: string, posB: string): number;
@@ -1,106 +0,0 @@
1
- export const min = 32;
2
- export const max = 126;
3
- export function makePosition(before, after) {
4
- // No children
5
- if (before == null && after == null) {
6
- return pos([min + 1]);
7
- }
8
- // Insert at the end
9
- if (before != null && after == null) {
10
- return getNextPosition(before);
11
- }
12
- // Insert at the start
13
- if (before == null && after != null) {
14
- return getPreviousPosition(after);
15
- }
16
- return pos(makePositionFromCodes(posCodes(before), posCodes(after)));
17
- }
18
- function getPreviousPosition(after) {
19
- const result = [];
20
- const afterCodes = posCodes(after);
21
- for (let i = 0; i < afterCodes.length; i++) {
22
- const code = afterCodes[i];
23
- if (code <= min + 1) {
24
- result.push(min);
25
- if (afterCodes.length - 1 === i) {
26
- result.push(max);
27
- break;
28
- }
29
- }
30
- else {
31
- result.push(code - 1);
32
- break;
33
- }
34
- }
35
- return pos(result);
36
- }
37
- function getNextPosition(before) {
38
- const result = [];
39
- const beforeCodes = posCodes(before);
40
- for (let i = 0; i < beforeCodes.length; i++) {
41
- const code = beforeCodes[i];
42
- if (code === max) {
43
- result.push(code);
44
- if (beforeCodes.length - 1 === i) {
45
- result.push(min + 1);
46
- break;
47
- }
48
- }
49
- else {
50
- result.push(code + 1);
51
- break;
52
- }
53
- }
54
- return pos(result);
55
- }
56
- function makePositionFromCodes(before, after) {
57
- let index = 0;
58
- const result = [];
59
- while (true) {
60
- const beforeDigit = before[index] || min;
61
- const afterDigit = after[index] || max;
62
- if (beforeDigit > afterDigit) {
63
- throw new Error(`Impossible to generate position between ${before} and ${after}`);
64
- }
65
- if (beforeDigit === afterDigit) {
66
- result.push(beforeDigit);
67
- index++;
68
- continue;
69
- }
70
- if (afterDigit - beforeDigit === 1) {
71
- result.push(beforeDigit);
72
- result.push(...makePositionFromCodes(before.slice(index + 1), []));
73
- break;
74
- }
75
- const mid = (afterDigit + beforeDigit) >> 1;
76
- result.push(mid);
77
- break;
78
- }
79
- return result;
80
- }
81
- export function posCodes(str) {
82
- const codes = [];
83
- for (let i = 0; i < str.length; i++) {
84
- codes.push(str.charCodeAt(i));
85
- }
86
- return codes;
87
- }
88
- export function pos(codes) {
89
- return String.fromCharCode(...codes);
90
- }
91
- export function compare(posA, posB) {
92
- const aCodes = posCodes(posA);
93
- const bCodes = posCodes(posB);
94
- const maxLength = Math.max(aCodes.length, bCodes.length);
95
- for (let i = 0; i < maxLength; i++) {
96
- const a = aCodes[i] == null ? min : aCodes[i];
97
- const b = bCodes[i] == null ? min : bCodes[i];
98
- if (a === b) {
99
- continue;
100
- }
101
- else {
102
- return a - b;
103
- }
104
- }
105
- throw new Error(`Impossible to compare similar position "${posA}" and "${posB}"`);
106
- }