@metriport/fhir-sdk 0.30.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +564 -0
- package/dist/__tests__/careplan.test.d.ts +2 -0
- package/dist/__tests__/careplan.test.d.ts.map +1 -0
- package/dist/__tests__/careplan.test.js +544 -0
- package/dist/__tests__/careplan.test.js.map +1 -0
- package/dist/__tests__/clinical-dates.test.d.ts +2 -0
- package/dist/__tests__/clinical-dates.test.d.ts.map +1 -0
- package/dist/__tests__/clinical-dates.test.js +341 -0
- package/dist/__tests__/clinical-dates.test.js.map +1 -0
- package/dist/__tests__/coding-utilities.test.d.ts +2 -0
- package/dist/__tests__/coding-utilities.test.d.ts.map +1 -0
- package/dist/__tests__/coding-utilities.test.js +482 -0
- package/dist/__tests__/coding-utilities.test.js.map +1 -0
- package/dist/__tests__/date-range-performance.test.d.ts +2 -0
- package/dist/__tests__/date-range-performance.test.d.ts.map +1 -0
- package/dist/__tests__/date-range-performance.test.js +218 -0
- package/dist/__tests__/date-range-performance.test.js.map +1 -0
- package/dist/__tests__/date-range-search.test.d.ts +2 -0
- package/dist/__tests__/date-range-search.test.d.ts.map +1 -0
- package/dist/__tests__/date-range-search.test.js +215 -0
- package/dist/__tests__/date-range-search.test.js.map +1 -0
- package/dist/__tests__/env-setup.d.ts +2 -0
- package/dist/__tests__/env-setup.d.ts.map +1 -0
- package/dist/__tests__/env-setup.js +37 -0
- package/dist/__tests__/env-setup.js.map +1 -0
- package/dist/__tests__/fhir-bundle-sdk-basic.test.d.ts +2 -0
- package/dist/__tests__/fhir-bundle-sdk-basic.test.d.ts.map +1 -0
- package/dist/__tests__/fhir-bundle-sdk-basic.test.js +19 -0
- package/dist/__tests__/fhir-bundle-sdk-basic.test.js.map +1 -0
- package/dist/__tests__/fhir-bundle-sdk.test.d.ts +2 -0
- package/dist/__tests__/fhir-bundle-sdk.test.d.ts.map +1 -0
- package/dist/__tests__/fhir-bundle-sdk.test.js +953 -0
- package/dist/__tests__/fhir-bundle-sdk.test.js.map +1 -0
- package/dist/__tests__/fixtures/fhir-bundles.d.ts +31 -0
- package/dist/__tests__/fixtures/fhir-bundles.d.ts.map +1 -0
- package/dist/__tests__/fixtures/fhir-bundles.js +487 -0
- package/dist/__tests__/fixtures/fhir-bundles.js.map +1 -0
- package/dist/__tests__/phase1-verification.test.d.ts +2 -0
- package/dist/__tests__/phase1-verification.test.d.ts.map +1 -0
- package/dist/__tests__/phase1-verification.test.js +141 -0
- package/dist/__tests__/phase1-verification.test.js.map +1 -0
- package/dist/__tests__/phase2-verification.test.d.ts +2 -0
- package/dist/__tests__/phase2-verification.test.d.ts.map +1 -0
- package/dist/__tests__/phase2-verification.test.js +234 -0
- package/dist/__tests__/phase2-verification.test.js.map +1 -0
- package/dist/__tests__/phase3-verification.test.d.ts +2 -0
- package/dist/__tests__/phase3-verification.test.d.ts.map +1 -0
- package/dist/__tests__/phase3-verification.test.js +121 -0
- package/dist/__tests__/phase3-verification.test.js.map +1 -0
- package/dist/__tests__/phase4-verification.test.d.ts +2 -0
- package/dist/__tests__/phase4-verification.test.d.ts.map +1 -0
- package/dist/__tests__/phase4-verification.test.js +168 -0
- package/dist/__tests__/phase4-verification.test.js.map +1 -0
- package/dist/__tests__/phase5-verification.test.d.ts +2 -0
- package/dist/__tests__/phase5-verification.test.d.ts.map +1 -0
- package/dist/__tests__/phase5-verification.test.js +397 -0
- package/dist/__tests__/phase5-verification.test.js.map +1 -0
- package/dist/__tests__/reverse-references.test.d.ts +2 -0
- package/dist/__tests__/reverse-references.test.d.ts.map +1 -0
- package/dist/__tests__/reverse-references.test.js +294 -0
- package/dist/__tests__/reverse-references.test.js.map +1 -0
- package/dist/__tests__/type-guards.test.d.ts +2 -0
- package/dist/__tests__/type-guards.test.d.ts.map +1 -0
- package/dist/__tests__/type-guards.test.js +163 -0
- package/dist/__tests__/type-guards.test.js.map +1 -0
- package/dist/clinical-dates.d.ts +26 -0
- package/dist/clinical-dates.d.ts.map +1 -0
- package/dist/clinical-dates.js +571 -0
- package/dist/clinical-dates.js.map +1 -0
- package/dist/fhir-bundle-sdk.d.ts +233 -0
- package/dist/fhir-bundle-sdk.d.ts.map +1 -0
- package/dist/fhir-bundle-sdk.js +545 -0
- package/dist/fhir-bundle-sdk.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/bundle-operations.d.ts +14 -0
- package/dist/internal/bundle-operations.d.ts.map +1 -0
- package/dist/internal/bundle-operations.js +55 -0
- package/dist/internal/bundle-operations.js.map +1 -0
- package/dist/internal/coding-systems.d.ts +48 -0
- package/dist/internal/coding-systems.d.ts.map +1 -0
- package/dist/internal/coding-systems.js +55 -0
- package/dist/internal/coding-systems.js.map +1 -0
- package/dist/internal/coding-utilities.d.ts +27 -0
- package/dist/internal/coding-utilities.d.ts.map +1 -0
- package/dist/internal/coding-utilities.js +297 -0
- package/dist/internal/coding-utilities.js.map +1 -0
- package/dist/internal/date-extraction.d.ts +12 -0
- package/dist/internal/date-extraction.d.ts.map +1 -0
- package/dist/internal/date-extraction.js +629 -0
- package/dist/internal/date-extraction.js.map +1 -0
- package/dist/internal/graph-traversal.d.ts +13 -0
- package/dist/internal/graph-traversal.d.ts.map +1 -0
- package/dist/internal/graph-traversal.js +89 -0
- package/dist/internal/graph-traversal.js.map +1 -0
- package/dist/internal/indexing.d.ts +17 -0
- package/dist/internal/indexing.d.ts.map +1 -0
- package/dist/internal/indexing.js +129 -0
- package/dist/internal/indexing.js.map +1 -0
- package/dist/internal/llm-context.d.ts +40 -0
- package/dist/internal/llm-context.d.ts.map +1 -0
- package/dist/internal/llm-context.js +214 -0
- package/dist/internal/llm-context.js.map +1 -0
- package/dist/internal/reference-resolution.d.ts +29 -0
- package/dist/internal/reference-resolution.d.ts.map +1 -0
- package/dist/internal/reference-resolution.js +338 -0
- package/dist/internal/reference-resolution.js.map +1 -0
- package/dist/internal/reference-utils.d.ts +26 -0
- package/dist/internal/reference-utils.d.ts.map +1 -0
- package/dist/internal/reference-utils.js +89 -0
- package/dist/internal/reference-utils.js.map +1 -0
- package/dist/internal/transparent-proxy.d.ts +12 -0
- package/dist/internal/transparent-proxy.d.ts.map +1 -0
- package/dist/internal/transparent-proxy.js +81 -0
- package/dist/internal/transparent-proxy.js.map +1 -0
- package/dist/internal/validation.d.ts +16 -0
- package/dist/internal/validation.d.ts.map +1 -0
- package/dist/internal/validation.js +45 -0
- package/dist/internal/validation.js.map +1 -0
- package/dist/type-guards.d.ts +212 -0
- package/dist/type-guards.d.ts.map +1 -0
- package/dist/type-guards.js +375 -0
- package/dist/type-guards.js.map +1 -0
- package/dist/types/coding-fields.d.ts +311 -0
- package/dist/types/coding-fields.d.ts.map +1 -0
- package/dist/types/coding-fields.js +3 -0
- package/dist/types/coding-fields.js.map +1 -0
- package/dist/types/sdk-types.d.ts +107 -0
- package/dist/types/sdk-types.d.ts.map +1 -0
- package/dist/types/sdk-types.js +17 -0
- package/dist/types/sdk-types.js.map +1 -0
- package/dist/types/smart-resources.d.ts +470 -0
- package/dist/types/smart-resources.d.ts.map +1 -0
- package/dist/types/smart-resources.js +249 -0
- package/dist/types/smart-resources.js.map +1 -0
- package/dist/utils/interval-tree/index.d.ts +87 -0
- package/dist/utils/interval-tree/index.d.ts.map +1 -0
- package/dist/utils/interval-tree/index.js +774 -0
- package/dist/utils/interval-tree/index.js.map +1 -0
- package/dist/utils/interval-tree/shallowequal/arrays.d.ts +3 -0
- package/dist/utils/interval-tree/shallowequal/arrays.d.ts.map +1 -0
- package/dist/utils/interval-tree/shallowequal/arrays.js +25 -0
- package/dist/utils/interval-tree/shallowequal/arrays.js.map +1 -0
- package/dist/utils/interval-tree/shallowequal/index.d.ts +6 -0
- package/dist/utils/interval-tree/shallowequal/index.d.ts.map +1 -0
- package/dist/utils/interval-tree/shallowequal/index.js +28 -0
- package/dist/utils/interval-tree/shallowequal/index.js.map +1 -0
- package/dist/utils/interval-tree/shallowequal/objects.d.ts +3 -0
- package/dist/utils/interval-tree/shallowequal/objects.d.ts.map +1 -0
- package/dist/utils/interval-tree/shallowequal/objects.js +28 -0
- package/dist/utils/interval-tree/shallowequal/objects.js.map +1 -0
- package/package.json +70 -0
|
@@ -0,0 +1,774 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
|
3
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
4
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
5
|
+
// @ts-nocheck
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.PreOrder = exports.ReverseInOrder = exports.InOrder = exports.IntervalTree = exports.Node = void 0;
|
|
8
|
+
// This file is a modified version of the original node-interval-tree library.
|
|
9
|
+
// We want to make as few / minimal changes as possible, and ignore lint errors.
|
|
10
|
+
// An augmented AVL Tree where each node maintains a list of records and their search intervals.
|
|
11
|
+
// Record is composed of an interval and its underlying data, sent by a client. This allows the
|
|
12
|
+
// interval tree to have the same interval inserted multiple times, as long its data is different.
|
|
13
|
+
// Both insertion and deletion require O(log n) time. Searching requires O(k*logn) time, where `k`
|
|
14
|
+
// is the number of intervals in the output list.
|
|
15
|
+
const shallowequal_1 = require("./shallowequal");
|
|
16
|
+
function max(a, b) {
|
|
17
|
+
return a < b ? b : a;
|
|
18
|
+
}
|
|
19
|
+
function height(node) {
|
|
20
|
+
if (node === undefined) {
|
|
21
|
+
return -1;
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
return node.height;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
class Node {
|
|
28
|
+
constructor(intervalTree, record) {
|
|
29
|
+
this.intervalTree = intervalTree;
|
|
30
|
+
this.records = [];
|
|
31
|
+
this.height = 0;
|
|
32
|
+
this.key = record.low;
|
|
33
|
+
this.max = record.high;
|
|
34
|
+
// Save the array of all records with the same key for this node
|
|
35
|
+
this.records.push(record);
|
|
36
|
+
}
|
|
37
|
+
// Gets the highest record.high value for this node
|
|
38
|
+
getNodeHigh() {
|
|
39
|
+
let high = this.records[0].high;
|
|
40
|
+
for (let i = 1; i < this.records.length; i++) {
|
|
41
|
+
if (this.records[i].high > high) {
|
|
42
|
+
high = this.records[i].high;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return high;
|
|
46
|
+
}
|
|
47
|
+
// Updates height value of the node. Called during insertion, rebalance, removal
|
|
48
|
+
updateHeight() {
|
|
49
|
+
this.height = max(height(this.left), height(this.right)) + 1;
|
|
50
|
+
}
|
|
51
|
+
// Updates the max value of all the parents after inserting into already existing node, as well as
|
|
52
|
+
// removing the node completely or removing the record of an already existing node. Starts with
|
|
53
|
+
// the parent of an affected node and bubbles up to root
|
|
54
|
+
updateMaxOfParents() {
|
|
55
|
+
if (this === undefined) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
const thisHigh = this.getNodeHigh();
|
|
59
|
+
if (this.left !== undefined && this.right !== undefined) {
|
|
60
|
+
this.max = max(max(this.left.max, this.right.max), thisHigh);
|
|
61
|
+
}
|
|
62
|
+
else if (this.left !== undefined && this.right === undefined) {
|
|
63
|
+
this.max = max(this.left.max, thisHigh);
|
|
64
|
+
}
|
|
65
|
+
else if (this.left === undefined && this.right !== undefined) {
|
|
66
|
+
this.max = max(this.right.max, thisHigh);
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
this.max = thisHigh;
|
|
70
|
+
}
|
|
71
|
+
if (this.parent) {
|
|
72
|
+
this.parent.updateMaxOfParents();
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/*
|
|
76
|
+
Left-Left case:
|
|
77
|
+
|
|
78
|
+
z y
|
|
79
|
+
/ \ / \
|
|
80
|
+
y T4 Right Rotate (z) x z
|
|
81
|
+
/ \ - - - - - - - - -> / \ / \
|
|
82
|
+
x T3 T1 T2 T3 T4
|
|
83
|
+
/ \
|
|
84
|
+
T1 T2
|
|
85
|
+
|
|
86
|
+
Left-Right case:
|
|
87
|
+
|
|
88
|
+
z z x
|
|
89
|
+
/ \ / \ / \
|
|
90
|
+
y T4 Left Rotate (y) x T4 Right Rotate(z) y z
|
|
91
|
+
/ \ - - - - - - - - -> / \ - - - - - - - -> / \ / \
|
|
92
|
+
T1 x y T3 T1 T2 T3 T4
|
|
93
|
+
/ \ / \
|
|
94
|
+
T2 T3 T1 T2
|
|
95
|
+
*/
|
|
96
|
+
// Handles Left-Left case and Left-Right case after rebalancing AVL tree
|
|
97
|
+
_updateMaxAfterRightRotate() {
|
|
98
|
+
const parent = this.parent;
|
|
99
|
+
const left = parent.left;
|
|
100
|
+
// Update max of left sibling (x in first case, y in second)
|
|
101
|
+
const thisParentLeftHigh = left.getNodeHigh();
|
|
102
|
+
if (left.left === undefined && left.right !== undefined) {
|
|
103
|
+
left.max = max(thisParentLeftHigh, left.right.max);
|
|
104
|
+
}
|
|
105
|
+
else if (left.left !== undefined && left.right === undefined) {
|
|
106
|
+
left.max = max(thisParentLeftHigh, left.left.max);
|
|
107
|
+
}
|
|
108
|
+
else if (left.left === undefined && left.right === undefined) {
|
|
109
|
+
left.max = thisParentLeftHigh;
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
left.max = max(max(left.left.max, left.right.max), thisParentLeftHigh);
|
|
113
|
+
}
|
|
114
|
+
// Update max of itself (z)
|
|
115
|
+
const thisHigh = this.getNodeHigh();
|
|
116
|
+
if (this.left === undefined && this.right !== undefined) {
|
|
117
|
+
this.max = max(thisHigh, this.right.max);
|
|
118
|
+
}
|
|
119
|
+
else if (this.left !== undefined && this.right === undefined) {
|
|
120
|
+
this.max = max(thisHigh, this.left.max);
|
|
121
|
+
}
|
|
122
|
+
else if (this.left === undefined && this.right === undefined) {
|
|
123
|
+
this.max = thisHigh;
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
this.max = max(max(this.left.max, this.right.max), thisHigh);
|
|
127
|
+
}
|
|
128
|
+
// Update max of parent (y in first case, x in second)
|
|
129
|
+
parent.max = max(max(parent.left.max, parent.right.max), parent.getNodeHigh());
|
|
130
|
+
}
|
|
131
|
+
/*
|
|
132
|
+
Right-Right case:
|
|
133
|
+
|
|
134
|
+
z y
|
|
135
|
+
/ \ / \
|
|
136
|
+
T1 y Left Rotate(z) z x
|
|
137
|
+
/ \ - - - - - - - -> / \ / \
|
|
138
|
+
T2 x T1 T2 T3 T4
|
|
139
|
+
/ \
|
|
140
|
+
T3 T4
|
|
141
|
+
|
|
142
|
+
Right-Left case:
|
|
143
|
+
|
|
144
|
+
z z x
|
|
145
|
+
/ \ / \ / \
|
|
146
|
+
T1 y Right Rotate (y) T1 x Left Rotate(z) z y
|
|
147
|
+
/ \ - - - - - - - - -> / \ - - - - - - - -> / \ / \
|
|
148
|
+
x T4 T2 y T1 T2 T3 T4
|
|
149
|
+
/ \ / \
|
|
150
|
+
T2 T3 T3 T4
|
|
151
|
+
*/
|
|
152
|
+
// Handles Right-Right case and Right-Left case in rebalancing AVL tree
|
|
153
|
+
_updateMaxAfterLeftRotate() {
|
|
154
|
+
const parent = this.parent;
|
|
155
|
+
const right = parent.right;
|
|
156
|
+
// Update max of right sibling (x in first case, y in second)
|
|
157
|
+
const thisParentRightHigh = right.getNodeHigh();
|
|
158
|
+
if (right.left === undefined && right.right !== undefined) {
|
|
159
|
+
right.max = max(thisParentRightHigh, right.right.max);
|
|
160
|
+
}
|
|
161
|
+
else if (right.left !== undefined && right.right === undefined) {
|
|
162
|
+
right.max = max(thisParentRightHigh, right.left.max);
|
|
163
|
+
}
|
|
164
|
+
else if (right.left === undefined && right.right === undefined) {
|
|
165
|
+
right.max = thisParentRightHigh;
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
right.max = max(max(right.left.max, right.right.max), thisParentRightHigh);
|
|
169
|
+
}
|
|
170
|
+
// Update max of itself (z)
|
|
171
|
+
const thisHigh = this.getNodeHigh();
|
|
172
|
+
if (this.left === undefined && this.right !== undefined) {
|
|
173
|
+
this.max = max(thisHigh, this.right.max);
|
|
174
|
+
}
|
|
175
|
+
else if (this.left !== undefined && this.right === undefined) {
|
|
176
|
+
this.max = max(thisHigh, this.left.max);
|
|
177
|
+
}
|
|
178
|
+
else if (this.left === undefined && this.right === undefined) {
|
|
179
|
+
this.max = thisHigh;
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
this.max = max(max(this.left.max, this.right.max), thisHigh);
|
|
183
|
+
}
|
|
184
|
+
// Update max of parent (y in first case, x in second)
|
|
185
|
+
parent.max = max(max(parent.left.max, right.max), parent.getNodeHigh());
|
|
186
|
+
}
|
|
187
|
+
_leftRotate() {
|
|
188
|
+
const rightChild = this.right;
|
|
189
|
+
rightChild.parent = this.parent;
|
|
190
|
+
if (rightChild.parent === undefined) {
|
|
191
|
+
this.intervalTree.root = rightChild;
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
if (rightChild.parent.left === this) {
|
|
195
|
+
rightChild.parent.left = rightChild;
|
|
196
|
+
}
|
|
197
|
+
else if (rightChild.parent.right === this) {
|
|
198
|
+
rightChild.parent.right = rightChild;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
this.right = rightChild.left;
|
|
202
|
+
if (this.right !== undefined) {
|
|
203
|
+
this.right.parent = this;
|
|
204
|
+
}
|
|
205
|
+
rightChild.left = this;
|
|
206
|
+
this.parent = rightChild;
|
|
207
|
+
this.updateHeight();
|
|
208
|
+
rightChild.updateHeight();
|
|
209
|
+
}
|
|
210
|
+
_rightRotate() {
|
|
211
|
+
const leftChild = this.left;
|
|
212
|
+
leftChild.parent = this.parent;
|
|
213
|
+
if (leftChild.parent === undefined) {
|
|
214
|
+
this.intervalTree.root = leftChild;
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
if (leftChild.parent.left === this) {
|
|
218
|
+
leftChild.parent.left = leftChild;
|
|
219
|
+
}
|
|
220
|
+
else if (leftChild.parent.right === this) {
|
|
221
|
+
leftChild.parent.right = leftChild;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
this.left = leftChild.right;
|
|
225
|
+
if (this.left !== undefined) {
|
|
226
|
+
this.left.parent = this;
|
|
227
|
+
}
|
|
228
|
+
leftChild.right = this;
|
|
229
|
+
this.parent = leftChild;
|
|
230
|
+
this.updateHeight();
|
|
231
|
+
leftChild.updateHeight();
|
|
232
|
+
}
|
|
233
|
+
// Rebalances the tree if the height value between two nodes of the same parent is greater than
|
|
234
|
+
// two. There are 4 cases that can happen which are outlined in the graphics above
|
|
235
|
+
_rebalance() {
|
|
236
|
+
if (height(this.left) >= 2 + height(this.right)) {
|
|
237
|
+
const left = this.left;
|
|
238
|
+
if (height(left.left) >= height(left.right)) {
|
|
239
|
+
// Left-Left case
|
|
240
|
+
this._rightRotate();
|
|
241
|
+
this._updateMaxAfterRightRotate();
|
|
242
|
+
}
|
|
243
|
+
else {
|
|
244
|
+
// Left-Right case
|
|
245
|
+
left._leftRotate();
|
|
246
|
+
this._rightRotate();
|
|
247
|
+
this._updateMaxAfterRightRotate();
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
else if (height(this.right) >= 2 + height(this.left)) {
|
|
251
|
+
const right = this.right;
|
|
252
|
+
if (height(right.right) >= height(right.left)) {
|
|
253
|
+
// Right-Right case
|
|
254
|
+
this._leftRotate();
|
|
255
|
+
this._updateMaxAfterLeftRotate();
|
|
256
|
+
}
|
|
257
|
+
else {
|
|
258
|
+
// Right-Left case
|
|
259
|
+
right._rightRotate();
|
|
260
|
+
this._leftRotate();
|
|
261
|
+
this._updateMaxAfterLeftRotate();
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
insert(record) {
|
|
266
|
+
if (record.low < this.key) {
|
|
267
|
+
// Insert into left subtree
|
|
268
|
+
if (this.left === undefined) {
|
|
269
|
+
this.left = new Node(this.intervalTree, record);
|
|
270
|
+
this.left.parent = this;
|
|
271
|
+
}
|
|
272
|
+
else {
|
|
273
|
+
this.left.insert(record);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
else {
|
|
277
|
+
// Insert into right subtree
|
|
278
|
+
if (this.right === undefined) {
|
|
279
|
+
this.right = new Node(this.intervalTree, record);
|
|
280
|
+
this.right.parent = this;
|
|
281
|
+
}
|
|
282
|
+
else {
|
|
283
|
+
this.right.insert(record);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
// Update the max value of this ancestor if needed
|
|
287
|
+
if (this.max < record.high) {
|
|
288
|
+
this.max = record.high;
|
|
289
|
+
}
|
|
290
|
+
// Update height of each node
|
|
291
|
+
this.updateHeight();
|
|
292
|
+
// Rebalance the tree to ensure all operations are executed in O(logn) time. This is especially
|
|
293
|
+
// important in searching, as the tree has a high chance of degenerating without the rebalancing
|
|
294
|
+
this._rebalance();
|
|
295
|
+
}
|
|
296
|
+
_getOverlappingRecords(currentNode, low, high) {
|
|
297
|
+
if (currentNode.key <= high && low <= currentNode.getNodeHigh()) {
|
|
298
|
+
// Nodes are overlapping, check if individual records in the node are overlapping
|
|
299
|
+
const tempResults = [];
|
|
300
|
+
for (let i = 0; i < currentNode.records.length; i++) {
|
|
301
|
+
if (currentNode.records[i].high >= low) {
|
|
302
|
+
tempResults.push(currentNode.records[i]);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
return tempResults;
|
|
306
|
+
}
|
|
307
|
+
return [];
|
|
308
|
+
}
|
|
309
|
+
search(low, high) {
|
|
310
|
+
// Don't search nodes that don't exist
|
|
311
|
+
if (this === undefined) {
|
|
312
|
+
return [];
|
|
313
|
+
}
|
|
314
|
+
let leftSearch = [];
|
|
315
|
+
let ownSearch = [];
|
|
316
|
+
let rightSearch = [];
|
|
317
|
+
// If interval is to the right of the rightmost point of any interval in this node and all its
|
|
318
|
+
// children, there won't be any matches
|
|
319
|
+
if (low > this.max) {
|
|
320
|
+
return [];
|
|
321
|
+
}
|
|
322
|
+
// Search left children
|
|
323
|
+
if (this.left !== undefined && this.left.max >= low) {
|
|
324
|
+
leftSearch = this.left.search(low, high);
|
|
325
|
+
}
|
|
326
|
+
// Check this node
|
|
327
|
+
ownSearch = this._getOverlappingRecords(this, low, high);
|
|
328
|
+
// If interval is to the left of the start of this interval, then it can't be in any child to
|
|
329
|
+
// the right
|
|
330
|
+
if (high < this.key) {
|
|
331
|
+
return leftSearch.concat(ownSearch);
|
|
332
|
+
}
|
|
333
|
+
// Otherwise, search right children
|
|
334
|
+
if (this.right !== undefined) {
|
|
335
|
+
rightSearch = this.right.search(low, high);
|
|
336
|
+
}
|
|
337
|
+
// Return accumulated results, if any
|
|
338
|
+
return leftSearch.concat(ownSearch, rightSearch);
|
|
339
|
+
}
|
|
340
|
+
// Searches for a node by a `key` value
|
|
341
|
+
searchExisting(low) {
|
|
342
|
+
if (this === undefined) {
|
|
343
|
+
return undefined;
|
|
344
|
+
}
|
|
345
|
+
if (this.key === low) {
|
|
346
|
+
return this;
|
|
347
|
+
}
|
|
348
|
+
else if (low < this.key) {
|
|
349
|
+
if (this.left !== undefined) {
|
|
350
|
+
return this.left.searchExisting(low);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
else {
|
|
354
|
+
if (this.right !== undefined) {
|
|
355
|
+
return this.right.searchExisting(low);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
return undefined;
|
|
359
|
+
}
|
|
360
|
+
// Returns the smallest node of the subtree
|
|
361
|
+
_minValue() {
|
|
362
|
+
if (this.left === undefined) {
|
|
363
|
+
return this;
|
|
364
|
+
}
|
|
365
|
+
else {
|
|
366
|
+
return this.left._minValue();
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
remove(node) {
|
|
370
|
+
const parent = this.parent;
|
|
371
|
+
if (node.key < this.key) {
|
|
372
|
+
// Node to be removed is on the left side
|
|
373
|
+
if (this.left !== undefined) {
|
|
374
|
+
return this.left.remove(node);
|
|
375
|
+
}
|
|
376
|
+
else {
|
|
377
|
+
return undefined;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
else if (node.key > this.key) {
|
|
381
|
+
// Node to be removed is on the right side
|
|
382
|
+
if (this.right !== undefined) {
|
|
383
|
+
return this.right.remove(node);
|
|
384
|
+
}
|
|
385
|
+
else {
|
|
386
|
+
return undefined;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
else {
|
|
390
|
+
if (this.left !== undefined && this.right !== undefined) {
|
|
391
|
+
// Node has two children
|
|
392
|
+
const minValue = this.right._minValue();
|
|
393
|
+
this.key = minValue.key;
|
|
394
|
+
this.records = minValue.records;
|
|
395
|
+
return this.right.remove(this);
|
|
396
|
+
}
|
|
397
|
+
else if (parent.left === this) {
|
|
398
|
+
// One child or no child case on left side
|
|
399
|
+
if (this.right !== undefined) {
|
|
400
|
+
parent.left = this.right;
|
|
401
|
+
this.right.parent = parent;
|
|
402
|
+
}
|
|
403
|
+
else {
|
|
404
|
+
parent.left = this.left;
|
|
405
|
+
if (this.left !== undefined) {
|
|
406
|
+
this.left.parent = parent;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
parent.updateMaxOfParents();
|
|
410
|
+
parent.updateHeight();
|
|
411
|
+
parent._rebalance();
|
|
412
|
+
return this;
|
|
413
|
+
}
|
|
414
|
+
else if (parent.right === this) {
|
|
415
|
+
// One child or no child case on right side
|
|
416
|
+
if (this.right !== undefined) {
|
|
417
|
+
parent.right = this.right;
|
|
418
|
+
this.right.parent = parent;
|
|
419
|
+
}
|
|
420
|
+
else {
|
|
421
|
+
parent.right = this.left;
|
|
422
|
+
if (this.left !== undefined) {
|
|
423
|
+
this.left.parent = parent;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
parent.updateMaxOfParents();
|
|
427
|
+
parent.updateHeight();
|
|
428
|
+
parent._rebalance();
|
|
429
|
+
return this;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
// Make linter happy
|
|
433
|
+
return undefined;
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
exports.Node = Node;
|
|
437
|
+
class IntervalTree {
|
|
438
|
+
constructor() {
|
|
439
|
+
this.count = 0;
|
|
440
|
+
}
|
|
441
|
+
insert(record) {
|
|
442
|
+
if (record.low > record.high) {
|
|
443
|
+
throw new Error("`low` value must be lower or equal to `high` value");
|
|
444
|
+
}
|
|
445
|
+
if (this.root === undefined) {
|
|
446
|
+
// Base case: Tree is empty, new node becomes root
|
|
447
|
+
this.root = new Node(this, record);
|
|
448
|
+
this.count++;
|
|
449
|
+
return true;
|
|
450
|
+
}
|
|
451
|
+
else {
|
|
452
|
+
// Otherwise, check if node already exists with the same key
|
|
453
|
+
const node = this.root.searchExisting(record.low);
|
|
454
|
+
if (node !== undefined) {
|
|
455
|
+
// Check the records in this node if there already is the one with same low, high, data
|
|
456
|
+
for (let i = 0; i < node.records.length; i++) {
|
|
457
|
+
if ((0, shallowequal_1.shallowEqual)(node.records[i], record)) {
|
|
458
|
+
// This record is same as the one we're trying to insert; return false to indicate
|
|
459
|
+
// nothing has been inserted
|
|
460
|
+
return false;
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
// Add the record to the node
|
|
464
|
+
node.records.push(record);
|
|
465
|
+
// Update max of the node and its parents if necessary
|
|
466
|
+
if (record.high > node.max) {
|
|
467
|
+
node.max = record.high;
|
|
468
|
+
if (node.parent) {
|
|
469
|
+
node.parent.updateMaxOfParents();
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
this.count++;
|
|
473
|
+
return true;
|
|
474
|
+
}
|
|
475
|
+
else {
|
|
476
|
+
// Node with this key doesn't already exist. Call insert function on root's node
|
|
477
|
+
this.root.insert(record);
|
|
478
|
+
this.count++;
|
|
479
|
+
return true;
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
search(low, high) {
|
|
484
|
+
if (this.root === undefined) {
|
|
485
|
+
// Tree is empty; return empty array
|
|
486
|
+
return [];
|
|
487
|
+
}
|
|
488
|
+
else {
|
|
489
|
+
return this.root.search(low, high);
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
remove(record) {
|
|
493
|
+
if (this.root === undefined) {
|
|
494
|
+
// Tree is empty; nothing to remove
|
|
495
|
+
return false;
|
|
496
|
+
}
|
|
497
|
+
else {
|
|
498
|
+
const node = this.root.searchExisting(record.low);
|
|
499
|
+
if (node === undefined) {
|
|
500
|
+
return false;
|
|
501
|
+
}
|
|
502
|
+
else if (node.records.length > 1) {
|
|
503
|
+
let removedRecord;
|
|
504
|
+
// Node with this key has 2 or more records. Find the one we need and remove it
|
|
505
|
+
for (let i = 0; i < node.records.length; i++) {
|
|
506
|
+
if ((0, shallowequal_1.shallowEqual)(node.records[i], record)) {
|
|
507
|
+
removedRecord = node.records[i];
|
|
508
|
+
node.records.splice(i, 1);
|
|
509
|
+
break;
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
if (removedRecord) {
|
|
513
|
+
removedRecord = undefined;
|
|
514
|
+
// Update max of that node and its parents if necessary
|
|
515
|
+
if (record.high === node.max) {
|
|
516
|
+
const nodeHigh = node.getNodeHigh();
|
|
517
|
+
if (node.left !== undefined && node.right !== undefined) {
|
|
518
|
+
node.max = max(max(node.left.max, node.right.max), nodeHigh);
|
|
519
|
+
}
|
|
520
|
+
else if (node.left !== undefined && node.right === undefined) {
|
|
521
|
+
node.max = max(node.left.max, nodeHigh);
|
|
522
|
+
}
|
|
523
|
+
else if (node.left === undefined && node.right !== undefined) {
|
|
524
|
+
node.max = max(node.right.max, nodeHigh);
|
|
525
|
+
}
|
|
526
|
+
else {
|
|
527
|
+
node.max = nodeHigh;
|
|
528
|
+
}
|
|
529
|
+
if (node.parent) {
|
|
530
|
+
node.parent.updateMaxOfParents();
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
this.count--;
|
|
534
|
+
return true;
|
|
535
|
+
}
|
|
536
|
+
else {
|
|
537
|
+
return false;
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
else if (node.records.length === 1) {
|
|
541
|
+
// Node with this key has only 1 record. Check if the remaining record in this node is
|
|
542
|
+
// actually the one we want to remove
|
|
543
|
+
if ((0, shallowequal_1.shallowEqual)(node.records[0], record)) {
|
|
544
|
+
// The remaining record is the one we want to remove. Remove the whole node from the tree
|
|
545
|
+
if (this.root.key === node.key) {
|
|
546
|
+
// We're removing the root element. Create a dummy node that will temporarily take
|
|
547
|
+
// root's parent role
|
|
548
|
+
const rootParent = new Node(this, { low: record.low, high: record.low });
|
|
549
|
+
rootParent.left = this.root;
|
|
550
|
+
this.root.parent = rootParent;
|
|
551
|
+
let removedNode = this.root.remove(node);
|
|
552
|
+
this.root = rootParent.left;
|
|
553
|
+
if (this.root !== undefined) {
|
|
554
|
+
this.root.parent = undefined;
|
|
555
|
+
}
|
|
556
|
+
if (removedNode) {
|
|
557
|
+
removedNode = undefined;
|
|
558
|
+
this.count--;
|
|
559
|
+
return true;
|
|
560
|
+
}
|
|
561
|
+
else {
|
|
562
|
+
return false;
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
else {
|
|
566
|
+
let removedNode = this.root.remove(node);
|
|
567
|
+
if (removedNode) {
|
|
568
|
+
removedNode = undefined;
|
|
569
|
+
this.count--;
|
|
570
|
+
return true;
|
|
571
|
+
}
|
|
572
|
+
else {
|
|
573
|
+
return false;
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
else {
|
|
578
|
+
// The remaining record is not the one we want to remove
|
|
579
|
+
return false;
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
else {
|
|
583
|
+
// No records at all in this node?! Shouldn't happen
|
|
584
|
+
return false;
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
inOrder() {
|
|
589
|
+
return new InOrder(this.root);
|
|
590
|
+
}
|
|
591
|
+
reverseInOrder() {
|
|
592
|
+
return new ReverseInOrder(this.root);
|
|
593
|
+
}
|
|
594
|
+
preOrder() {
|
|
595
|
+
return new PreOrder(this.root);
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
exports.IntervalTree = IntervalTree;
|
|
599
|
+
/**
|
|
600
|
+
* The default export just wraps the `IntervalTree`, while providing a simpler API. Check out the
|
|
601
|
+
* README for description on how to use each.
|
|
602
|
+
*/
|
|
603
|
+
class DataIntervalTree {
|
|
604
|
+
constructor() {
|
|
605
|
+
this.tree = new IntervalTree();
|
|
606
|
+
}
|
|
607
|
+
insert(low, high, data) {
|
|
608
|
+
return this.tree.insert({ low, high, data });
|
|
609
|
+
}
|
|
610
|
+
remove(low, high, data) {
|
|
611
|
+
return this.tree.remove({ low, high, data });
|
|
612
|
+
}
|
|
613
|
+
search(low, high) {
|
|
614
|
+
return this.tree.search(low, high).map(v => v.data);
|
|
615
|
+
}
|
|
616
|
+
inOrder() {
|
|
617
|
+
return this.tree.inOrder();
|
|
618
|
+
}
|
|
619
|
+
reverseInOrder() {
|
|
620
|
+
return this.tree.reverseInOrder();
|
|
621
|
+
}
|
|
622
|
+
preOrder() {
|
|
623
|
+
return this.tree.preOrder();
|
|
624
|
+
}
|
|
625
|
+
get count() {
|
|
626
|
+
return this.tree.count;
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
exports.default = DataIntervalTree;
|
|
630
|
+
class InOrder {
|
|
631
|
+
constructor(startNode) {
|
|
632
|
+
this.stack = [];
|
|
633
|
+
if (startNode !== undefined) {
|
|
634
|
+
this.push(startNode);
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
[Symbol.iterator]() {
|
|
638
|
+
return this;
|
|
639
|
+
}
|
|
640
|
+
next() {
|
|
641
|
+
// Will only happen if stack is empty and pop is called
|
|
642
|
+
if (this.currentNode === undefined) {
|
|
643
|
+
return {
|
|
644
|
+
done: true,
|
|
645
|
+
value: undefined,
|
|
646
|
+
};
|
|
647
|
+
}
|
|
648
|
+
// Process this node
|
|
649
|
+
if (this.i < this.currentNode.records.length) {
|
|
650
|
+
return {
|
|
651
|
+
done: false,
|
|
652
|
+
value: this.currentNode.records[this.i++],
|
|
653
|
+
};
|
|
654
|
+
}
|
|
655
|
+
if (this.currentNode.right !== undefined) {
|
|
656
|
+
// Can we go right?
|
|
657
|
+
this.push(this.currentNode.right);
|
|
658
|
+
}
|
|
659
|
+
else {
|
|
660
|
+
// Otherwise go up
|
|
661
|
+
// Might pop the last and set this.currentNode = undefined
|
|
662
|
+
this.pop();
|
|
663
|
+
}
|
|
664
|
+
return this.next();
|
|
665
|
+
}
|
|
666
|
+
push(node) {
|
|
667
|
+
this.currentNode = node;
|
|
668
|
+
this.i = 0;
|
|
669
|
+
while (this.currentNode.left !== undefined) {
|
|
670
|
+
this.stack.push(this.currentNode);
|
|
671
|
+
this.currentNode = this.currentNode.left;
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
pop() {
|
|
675
|
+
this.currentNode = this.stack.pop();
|
|
676
|
+
this.i = 0;
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
exports.InOrder = InOrder;
|
|
680
|
+
class ReverseInOrder {
|
|
681
|
+
constructor(startNode) {
|
|
682
|
+
this.stack = [];
|
|
683
|
+
if (startNode !== undefined) {
|
|
684
|
+
this.push(startNode);
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
[Symbol.iterator]() {
|
|
688
|
+
return this;
|
|
689
|
+
}
|
|
690
|
+
next() {
|
|
691
|
+
// Will only happen if stack is empty and pop is called
|
|
692
|
+
if (this.currentNode === undefined) {
|
|
693
|
+
return {
|
|
694
|
+
done: true,
|
|
695
|
+
value: undefined,
|
|
696
|
+
};
|
|
697
|
+
}
|
|
698
|
+
// Process this node
|
|
699
|
+
if (this.currentNode.records.length && this.i >= 0) {
|
|
700
|
+
return {
|
|
701
|
+
done: false,
|
|
702
|
+
value: this.currentNode.records[this.i--],
|
|
703
|
+
};
|
|
704
|
+
}
|
|
705
|
+
if (this.currentNode.left !== undefined) {
|
|
706
|
+
// Can we go left?
|
|
707
|
+
this.push(this.currentNode.left);
|
|
708
|
+
}
|
|
709
|
+
else {
|
|
710
|
+
// Otherwise go up
|
|
711
|
+
// Might pop the last and set this.currentNode = undefined
|
|
712
|
+
this.pop();
|
|
713
|
+
}
|
|
714
|
+
return this.next();
|
|
715
|
+
}
|
|
716
|
+
push(node) {
|
|
717
|
+
this.currentNode = node;
|
|
718
|
+
this.i = (this.currentNode?.records.length ?? 0) - 1;
|
|
719
|
+
while (this.currentNode.right !== undefined) {
|
|
720
|
+
this.stack.push(this.currentNode);
|
|
721
|
+
this.currentNode = this.currentNode.right;
|
|
722
|
+
this.i = (this.currentNode?.records.length ?? 0) - 1;
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
pop() {
|
|
726
|
+
this.currentNode = this.stack.pop();
|
|
727
|
+
this.i = (this.currentNode?.records.length ?? 0) - 1;
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
exports.ReverseInOrder = ReverseInOrder;
|
|
731
|
+
class PreOrder {
|
|
732
|
+
constructor(startNode) {
|
|
733
|
+
this.stack = [];
|
|
734
|
+
this.i = 0;
|
|
735
|
+
this.currentNode = startNode;
|
|
736
|
+
}
|
|
737
|
+
[Symbol.iterator]() {
|
|
738
|
+
return this;
|
|
739
|
+
}
|
|
740
|
+
next() {
|
|
741
|
+
// Will only happen if stack is empty and pop is called,
|
|
742
|
+
// which only happens if there is no right node (i.e we are done)
|
|
743
|
+
if (this.currentNode === undefined) {
|
|
744
|
+
return {
|
|
745
|
+
done: true,
|
|
746
|
+
value: undefined,
|
|
747
|
+
};
|
|
748
|
+
}
|
|
749
|
+
// Process this node
|
|
750
|
+
if (this.i < this.currentNode.records.length) {
|
|
751
|
+
return {
|
|
752
|
+
done: false,
|
|
753
|
+
value: this.currentNode.records[this.i++],
|
|
754
|
+
};
|
|
755
|
+
}
|
|
756
|
+
if (this.currentNode.right !== undefined) {
|
|
757
|
+
this.push(this.currentNode.right);
|
|
758
|
+
}
|
|
759
|
+
if (this.currentNode.left !== undefined) {
|
|
760
|
+
this.push(this.currentNode.left);
|
|
761
|
+
}
|
|
762
|
+
this.pop();
|
|
763
|
+
return this.next();
|
|
764
|
+
}
|
|
765
|
+
push(node) {
|
|
766
|
+
this.stack.push(node);
|
|
767
|
+
}
|
|
768
|
+
pop() {
|
|
769
|
+
this.currentNode = this.stack.pop();
|
|
770
|
+
this.i = 0;
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
exports.PreOrder = PreOrder;
|
|
774
|
+
//# sourceMappingURL=index.js.map
|