@teselagen/range-utils 0.1.20 → 0.1.22

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 (90) hide show
  1. package/index.js +6542 -18010
  2. package/index.mjs +6593 -18007
  3. package/index.umd.js +6836 -18306
  4. package/package.json +1 -1
  5. package/src/adjustRangeToDeletionOfAnotherRange.js +53 -0
  6. package/src/adjustRangeToDeletionOfAnotherRange.test.js +107 -0
  7. package/src/adjustRangeToInsert.js +28 -0
  8. package/src/adjustRangeToInsert.test.js +111 -0
  9. package/src/adjustRangeToRotation.js +24 -0
  10. package/src/adjustRangeToRotation.test.js +123 -0
  11. package/src/checkIfNonCircularRangesOverlap.js +30 -0
  12. package/src/checkIfNonCircularRangesOverlap.test.js +45 -0
  13. package/src/checkIfPotentiallyCircularRangesOverlap.js +16 -0
  14. package/src/checkIfPotentiallyCircularRangesOverlap.test.js +73 -0
  15. package/src/collapseOverlapsGeneratedFromRangeComparisonIfPossible.js +47 -0
  16. package/src/collapseOverlapsGeneratedFromRangeComparisonIfPossible.test.js +124 -0
  17. package/src/convertRangeIndices.js +22 -0
  18. package/src/convertRangeIndices.test.js +22 -0
  19. package/src/convertRangeTo0Based.js +5 -0
  20. package/src/convertRangeTo1Based.js +5 -0
  21. package/src/doesRangeSpanEntireSequence.js +7 -0
  22. package/src/doesRangeSpanOrigin.js +3 -0
  23. package/src/expandOrContractCircularRangeToPosition.js +41 -0
  24. package/src/expandOrContractNonCircularRangeToPosition.js +25 -0
  25. package/src/expandOrContractRangeByLength.js +12 -0
  26. package/src/expandOrContractRangeByLength.test.js +77 -0
  27. package/src/expandOrContractRangeToPosition.js +10 -0
  28. package/src/flipContainedRange.js +85 -0
  29. package/src/flipContainedRange.test.js +124 -0
  30. package/src/generateRandomRange.js +20 -0
  31. package/src/generateRandomRange.test.js +24 -0
  32. package/src/getAnnotationRangeType.js +24 -0
  33. package/src/getAnnotationRangeType.test.js +59 -0
  34. package/src/getEachPositionInRangeAsArray.js +15 -0
  35. package/src/getEachPositionInRangeAsArray.test.js +9 -0
  36. package/src/getLengthOfOverlappingRegionsBetweenTwoRanges.js +9 -0
  37. package/src/getLengthOfOverlappingRegionsBetweenTwoRanges.test.js +24 -0
  38. package/src/getMiddleOfRange.js +10 -0
  39. package/src/getMiddleOfRange.test.js +44 -0
  40. package/src/getOverlapOfNonCircularRanges.js +35 -0
  41. package/src/getOverlapsOfPotentiallyCircularRanges.js +54 -0
  42. package/src/getOverlapsOfPotentiallyCircularRanges.test.js +199 -0
  43. package/src/getPositionFromAngle.js +7 -0
  44. package/src/getRangeAngles.js +33 -0
  45. package/src/getRangeAngles.test.js +77 -0
  46. package/src/getRangeLength.js +14 -0
  47. package/src/getRangeLength.test.js +30 -0
  48. package/src/getRangesBetweenTwoRanges.js +28 -0
  49. package/src/getSequenceWithinRange.js +17 -0
  50. package/src/getSequenceWithinRange.test.js +49 -0
  51. package/src/getShortestDistanceBetweenTwoPositions.js +12 -0
  52. package/src/getShortestDistanceBetweenTwoPositions.test.js +14 -0
  53. package/src/getYOffsetForPotentiallyCircularRange.js +24 -0
  54. package/src/getYOffsetsForPotentiallyCircularRanges.js +20 -0
  55. package/src/getYOffsetsForPotentiallyCircularRanges.test.js +29 -0
  56. package/src/getZeroedRangeOverlaps.js +17 -0
  57. package/src/getZeroedRangeOverlaps.test.js +36 -0
  58. package/src/index.js +51 -0
  59. package/src/index.test.js +33 -0
  60. package/src/invertRange.js +21 -0
  61. package/src/invertRange.test.js +96 -0
  62. package/src/isPositionCloserToRangeStartThanRangeEnd.js +8 -0
  63. package/src/isPositionCloserToRangeStartThanRangeEnd.test.js +17 -0
  64. package/src/isPositionWithinRange.js +31 -0
  65. package/src/isRangeOrPositionWithinRange.js +29 -0
  66. package/src/isRangeOrPositionWithinRange.test.js +150 -0
  67. package/src/isRangeWithinRange.js +17 -0
  68. package/src/loopEachPositionInRange.js +5 -0
  69. package/src/modulatePositionByRange.js +10 -0
  70. package/src/modulatePositionByRange.test.js +12 -0
  71. package/src/modulateRangeBySequenceLength.js +11 -0
  72. package/src/modulateRangeBySequenceLength.test.js +16 -0
  73. package/src/normalizePositionByRangeLength.js +20 -0
  74. package/src/normalizePositionByRangeLength.test.js +23 -0
  75. package/src/normalizePositionByRangeLength1Based.js +5 -0
  76. package/src/normalizePositionByRangeLength1Based.test.js +9 -0
  77. package/src/normalizeRange.js +11 -0
  78. package/src/normalizeRange.test.js +9 -0
  79. package/src/provideInclusiveOptions.js +26 -0
  80. package/src/reversePositionInRange.js +13 -0
  81. package/src/splitRangeIntoTwoPartsIfItIsCircular.js +31 -0
  82. package/src/splitRangeIntoTwoPartsIfItIsCircular.test.js +33 -0
  83. package/src/translateRange.js +9 -0
  84. package/src/translateRange.test.js +20 -0
  85. package/src/trimNonCicularRangeByAnotherNonCircularRange.js +57 -0
  86. package/src/trimNumberToFitWithin0ToAnotherNumber.js +12 -0
  87. package/src/trimRangeByAnotherRange.js +102 -0
  88. package/src/trimRangeByAnotherRange.test.js +314 -0
  89. package/src/zeroSubrangeByContainerRange.js +36 -0
  90. package/src/zeroSubrangeByContainerRange.test.js +51 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@teselagen/range-utils",
3
- "version": "0.1.20",
3
+ "version": "0.1.22",
4
4
  "type": "commonjs",
5
5
  "dependencies": {
6
6
  "lodash": "^4.17.21"
@@ -0,0 +1,53 @@
1
+ import splitRangeIntoTwoPartsIfItIsCircular from "./splitRangeIntoTwoPartsIfItIsCircular";
2
+ import trimRangeByAnotherRange from "./trimRangeByAnotherRange";
3
+
4
+ //takes in two potentially circular ranges and returns the first one trimmed by the second one
5
+ //returns null if no range is left after the trimming
6
+ export default function adjustRangeToDeletionOfAnotherRange(
7
+ rangeToBeAdjusted,
8
+ anotherRange,
9
+ maxLength
10
+ ) {
11
+ // ac.throw(ac.range, rangeToBeAdjusted)
12
+ // ac.throw(ac.range, anotherRange)
13
+ // ac.throw(ac.posInt, maxLength)
14
+
15
+ const trimmedRange = trimRangeByAnotherRange(
16
+ rangeToBeAdjusted,
17
+ anotherRange,
18
+ maxLength
19
+ );
20
+ if (trimmedRange) {
21
+ //if there is a range left after being trimmed, adjust it by the deleted anotherRange
22
+ //we can make some awesome logical simplifications because we know that the two ranges do not overlap (since we've already trimmed the rangeToBeAdjusted)
23
+ const nonCircularDeletionRanges = splitRangeIntoTwoPartsIfItIsCircular(
24
+ anotherRange,
25
+ maxLength
26
+ );
27
+ nonCircularDeletionRanges.forEach(function (nonCircularDeletionRange) {
28
+ const deletionLength =
29
+ nonCircularDeletionRange.end - nonCircularDeletionRange.start + 1;
30
+ if (trimmedRange.start > trimmedRange.end) {
31
+ //the trimmed range is circular
32
+ if (nonCircularDeletionRange.start < trimmedRange.end) {
33
+ trimmedRange.start -= deletionLength;
34
+ trimmedRange.end -= deletionLength;
35
+ } else if (nonCircularDeletionRange.start < trimmedRange.start) {
36
+ trimmedRange.start -= deletionLength;
37
+ } else {
38
+ //do nothing
39
+ }
40
+ } else {
41
+ if (nonCircularDeletionRange.start < trimmedRange.start) {
42
+ trimmedRange.start -= deletionLength;
43
+ trimmedRange.end -= deletionLength;
44
+ } else if (nonCircularDeletionRange.start < trimmedRange.end) {
45
+ trimmedRange.end -= deletionLength;
46
+ } else {
47
+ //do nothing
48
+ }
49
+ }
50
+ });
51
+ }
52
+ return trimmedRange;
53
+ }
@@ -0,0 +1,107 @@
1
+
2
+
3
+ import adjustRangeToDeletionOfAnotherRange from './adjustRangeToDeletionOfAnotherRange.js';
4
+
5
+ import assert from 'assert';
6
+ describe('adjustRangeToDeletionOfAnotherRange', function() {
7
+ it('deletes non circular range if fully overlapped', function() {
8
+ assert.deepEqual(adjustRangeToDeletionOfAnotherRange({
9
+ start: 10,
10
+ end: 20
11
+ }, {
12
+ start: 10,
13
+ end: 20
14
+ }, 30), null);
15
+ });
16
+ it('deletes circular range if fully overlapped', function() {
17
+ assert.deepEqual(adjustRangeToDeletionOfAnotherRange({
18
+ start: 20,
19
+ end: 10
20
+ }, {
21
+ start: 20,
22
+ end: 10
23
+ }, 30), null);
24
+ });
25
+ it('shifts start and end if deleting before non circular range', function() {
26
+ assert.deepEqual(adjustRangeToDeletionOfAnotherRange({
27
+ name: 'happy',
28
+ start: 10,
29
+ end: 20
30
+ }, {
31
+ start: 5,
32
+ end: 8
33
+ }, 30), {
34
+ name: 'happy',
35
+ start: 6,
36
+ end: 16
37
+ });
38
+ });
39
+ it('shifts start if deleting in middle of non circular range', function() {
40
+ assert.deepEqual(adjustRangeToDeletionOfAnotherRange({
41
+ name: 'happy',
42
+ start: 20,
43
+ end: 10
44
+ }, {
45
+ start: 15,
46
+ end: 20
47
+ }, 30), {
48
+ name: 'happy',
49
+ start: 15,
50
+ end: 10
51
+ });
52
+ assert.deepEqual(adjustRangeToDeletionOfAnotherRange({
53
+ start: 20,
54
+ end: 10
55
+ }, {
56
+ start: 15,
57
+ end: 15
58
+ }, 30), {
59
+ start: 19,
60
+ end: 10
61
+ });
62
+ });
63
+ it('shifts start and end if deleting before end of non circular range', function() {
64
+ assert.deepEqual(adjustRangeToDeletionOfAnotherRange({
65
+ start: 20,
66
+ end: 10
67
+ }, {
68
+ start: 0,
69
+ end: 0
70
+ }, 30), {
71
+ start: 19,
72
+ end: 9
73
+ });
74
+ assert.deepEqual(adjustRangeToDeletionOfAnotherRange({
75
+ start: 20,
76
+ end: 10
77
+ }, {
78
+ start: 5,
79
+ end: 15
80
+ }, 30), {
81
+ start: 9,
82
+ end: 4
83
+ });
84
+ });
85
+ it('shifts neither start nor end if deleting after start of non circular range', function() {
86
+ assert.deepEqual(adjustRangeToDeletionOfAnotherRange({
87
+ start: 20,
88
+ end: 10
89
+ }, {
90
+ start: 25,
91
+ end: 27
92
+ }, 30), {
93
+ start: 20,
94
+ end: 10
95
+ });
96
+ assert.deepEqual(adjustRangeToDeletionOfAnotherRange({
97
+ start: 20,
98
+ end: 10
99
+ }, {
100
+ start: 20,
101
+ end: 25
102
+ }, 30), {
103
+ start: 20,
104
+ end: 10
105
+ });
106
+ });
107
+ });
@@ -0,0 +1,28 @@
1
+
2
+ import {assign} from "lodash";
3
+
4
+ export default function adjustRangeToInsert(rangeToBeAdjusted, insertStart, insertLength) {
5
+ // ac.throw([ac.range, ac.posInt, ac.posInt], arguments);
6
+ const newRange = assign({}, rangeToBeAdjusted);
7
+ if (rangeToBeAdjusted.start > rangeToBeAdjusted.end) {
8
+ //circular range
9
+ if (rangeToBeAdjusted.end >= insertStart) {
10
+ //adjust both start and end
11
+ newRange.start += insertLength;
12
+ newRange.end += insertLength;
13
+ } else if (rangeToBeAdjusted.start >= insertStart) {
14
+ //adjust just the start
15
+ newRange.start += insertLength;
16
+ }
17
+ } else {
18
+ if (rangeToBeAdjusted.start >= insertStart) {
19
+ //adjust both start and end
20
+ newRange.start += insertLength;
21
+ newRange.end += insertLength;
22
+ } else if (rangeToBeAdjusted.end >= insertStart) {
23
+ //adjust just the end
24
+ newRange.end += insertLength;
25
+ }
26
+ }
27
+ return newRange;
28
+ };
@@ -0,0 +1,111 @@
1
+
2
+
3
+
4
+ import adjustRangeToInsert from './adjustRangeToInsert.js';
5
+
6
+ import assert from 'assert';
7
+ describe('adjustRangeToInsert', function() {
8
+ it('shifts start and end if inserting before non circular range', function() {
9
+ assert.deepEqual(adjustRangeToInsert({
10
+ start: 10,
11
+ end: 20
12
+ }, 4, 5), {
13
+ start: 15,
14
+ end: 25
15
+ });
16
+ assert.deepEqual(adjustRangeToInsert({
17
+ start: 10,
18
+ end: 20
19
+ }, 10, 5), {
20
+ start: 15,
21
+ end: 25
22
+ });
23
+ assert.deepEqual(adjustRangeToInsert({
24
+ start: 10,
25
+ end: 20
26
+ }, 0, 5), {
27
+ start: 15,
28
+ end: 25
29
+ });
30
+ });
31
+ it('shifts end if inserting in middle of non circular range', function() {
32
+ assert.deepEqual(adjustRangeToInsert({
33
+ start: 10,
34
+ end: 20
35
+ }, 11, 5), {
36
+ start: 10,
37
+ end: 25
38
+ });
39
+ assert.deepEqual(adjustRangeToInsert({
40
+ start: 10,
41
+ end: 20
42
+ }, 20, 5), {
43
+ start: 10,
44
+ end: 25
45
+ });
46
+ });
47
+ it('shifts neither start nor end if inserting in after end of non circular range', function() {
48
+ assert.deepEqual(adjustRangeToInsert({
49
+ start: 10,
50
+ end: 20
51
+ }, 24, 5), {
52
+ start: 10,
53
+ end: 20
54
+ });
55
+ assert.deepEqual(adjustRangeToInsert({
56
+ start: 10,
57
+ end: 20
58
+ }, 21, 5), {
59
+ start: 10,
60
+ end: 20
61
+ });
62
+ });
63
+ it('shifts neither start nor end if inserting in after start of circular range', function() {
64
+ assert.deepEqual(adjustRangeToInsert({
65
+ start: 20,
66
+ end: 10
67
+ }, 24, 5), {
68
+ start: 20,
69
+ end: 10
70
+ });
71
+ assert.deepEqual(adjustRangeToInsert({
72
+ start: 20,
73
+ end: 10
74
+ }, 21, 5), {
75
+ start: 20,
76
+ end: 10
77
+ });
78
+ });
79
+ it('shifts both start and end if inserting in before end of circular range', function() {
80
+ assert.deepEqual(adjustRangeToInsert({
81
+ start: 20,
82
+ end: 10
83
+ }, 5, 5), {
84
+ start: 25,
85
+ end: 15
86
+ });
87
+ assert.deepEqual(adjustRangeToInsert({
88
+ start: 20,
89
+ end: 10
90
+ }, 10, 5), {
91
+ start: 25,
92
+ end: 15
93
+ });
94
+ });
95
+ it('shifts just start if inserting in after end but before start of circular range', function() {
96
+ assert.deepEqual(adjustRangeToInsert({
97
+ start: 20,
98
+ end: 10
99
+ }, 11, 5), {
100
+ start: 25,
101
+ end: 10
102
+ });
103
+ assert.deepEqual(adjustRangeToInsert({
104
+ start: 20,
105
+ end: 10
106
+ }, 20, 5), {
107
+ start: 25,
108
+ end: 10
109
+ });
110
+ });
111
+ });
@@ -0,0 +1,24 @@
1
+
2
+ import {assign} from "lodash";
3
+
4
+ import {identity} from 'lodash';
5
+
6
+ export default function adjustRangeToRotation(
7
+ rangeToBeAdjusted,
8
+ rotateTo = 0,
9
+ rangeLength
10
+ ) {
11
+ // ac.throw([ac.range, ac.posInt, ac.posInt], arguments);
12
+ const mod = rangeLength ? modulo : identity
13
+
14
+ const newRange = assign({}, rangeToBeAdjusted, {
15
+ start: mod(rangeToBeAdjusted.start - (rotateTo || 0), rangeLength),
16
+ end: mod(rangeToBeAdjusted.end - (rotateTo || 0), rangeLength)
17
+ });
18
+
19
+ return newRange;
20
+ };
21
+
22
+ function modulo(n, m) {
23
+ return ((n % m) + m) % m;
24
+ }
@@ -0,0 +1,123 @@
1
+ import adjustRangeToRotation from './adjustRangeToRotation.js';
2
+
3
+ import assert from 'assert';
4
+
5
+
6
+ ;
7
+ describe('adjustRangeToRotation', function() {
8
+ it('defaults to a rotateBy=0 if a null or undefined is passed ', () => {
9
+ assert.deepEqual(adjustRangeToRotation({
10
+ start: 1,
11
+ end: 2
12
+ }, null, 10), {
13
+ start: 1,
14
+ end: 2
15
+ });
16
+
17
+ assert.deepEqual(adjustRangeToRotation({
18
+ start: 1,
19
+ end: 2
20
+ }, undefined, 10), {
21
+ start: 1,
22
+ end: 2
23
+ });
24
+ assert.deepEqual(adjustRangeToRotation({
25
+ start: 1,
26
+ end: 2
27
+ }, NaN, 10), {
28
+ start: 1,
29
+ end: 2
30
+ });
31
+
32
+ });
33
+ it('defaults to an infinite length if no length is passed', () => {
34
+ assert.deepEqual(adjustRangeToRotation({
35
+ start: 1,
36
+ end: 2
37
+ }, 1, null), {
38
+ start: 0,
39
+ end: 1
40
+ });
41
+ assert.deepEqual(adjustRangeToRotation({
42
+ start: 1,
43
+ end: 2
44
+ }, 1, undefined), {
45
+ start: 0,
46
+ end: 1
47
+ });
48
+
49
+
50
+
51
+ });
52
+ it('shifts start and end if rotating before non circular range', function() {
53
+ //0123456789
54
+ //atgcatgccc
55
+ // rr
56
+ //
57
+ assert.deepEqual(adjustRangeToRotation({
58
+ start: 1,
59
+ end: 2
60
+ }, 1, 10), {
61
+ start: 0,
62
+ end: 1
63
+ });
64
+ assert.deepEqual(adjustRangeToRotation({
65
+ start: 1,
66
+ end: 2
67
+ }, undefined, 10), {
68
+ start: 1,
69
+ end: 2
70
+ });
71
+ assert.deepEqual(adjustRangeToRotation({
72
+ start: 1,
73
+ end: 2
74
+ }, 2, 10), {
75
+ start: 9,
76
+ end: 0
77
+ });
78
+ assert.deepEqual(adjustRangeToRotation({
79
+ start: 1,
80
+ end: 2
81
+ }, 3, 10), {
82
+ start: 8,
83
+ end: 9
84
+ });
85
+ //0123456789
86
+ //atgcatgccc
87
+ //rrrrr rrr
88
+ //
89
+ assert.deepEqual(adjustRangeToRotation({
90
+ start: 7,
91
+ end: 4
92
+ }, 3, 10), {
93
+ start: 4,
94
+ end: 1
95
+ });
96
+ assert.deepEqual(adjustRangeToRotation({
97
+ start: 7,
98
+ end: 4
99
+ }, 5, 10), {
100
+ start: 2,
101
+ end: 9
102
+ });
103
+ assert.deepEqual(adjustRangeToRotation({
104
+ start: 7,
105
+ end: 4
106
+ }, 6, 10), {
107
+ start: 1,
108
+ end: 8
109
+ });
110
+ //0123456 789
111
+ //atgcatg ccc
112
+ //rrrrrrr rrr
113
+ //
114
+ assert.deepEqual(adjustRangeToRotation({
115
+ start: 7,
116
+ end: 6
117
+ }, 3, 10), {
118
+ start: 4,
119
+ end: 3
120
+ });
121
+ });
122
+
123
+ });
@@ -0,0 +1,30 @@
1
+ //
2
+ // ac.throw([ac.posInt, ac.posInt, ac.bool], arguments);
3
+ export default function checkIfNonCircularRangesOverlap(range, comparisonRange) {
4
+ // ac.throw([ac.range, ac.range], arguments);
5
+ if (range.start < comparisonRange.start) {
6
+ if (range.end < comparisonRange.start) {
7
+ //----llll
8
+ //--------cccc
9
+ //no overlap
10
+ return false;
11
+ } else {
12
+ //----llll
13
+ //-------cccc
14
+ //overlap
15
+ return true;
16
+ }
17
+ } else {
18
+ if (range.start > comparisonRange.end) {
19
+ //------llll
20
+ // -cccc
21
+ //no overlap
22
+ return false;
23
+ } else {
24
+ //-----llll
25
+ // -cccc
26
+ //overlap
27
+ return true;
28
+ }
29
+ }
30
+ };
@@ -0,0 +1,45 @@
1
+ import {expect} from 'chai';
2
+
3
+ import checkIfNonCircularRangesOverlap from './checkIfNonCircularRangesOverlap.js';
4
+ // checkIfNonCircularRangesOverlap(frame, sequence, minimumOrfSize, forward, circular)
5
+ describe('checkIfNonCircularRangesOverlap', function() {
6
+ it('returns true if non circular ranges do overlap', function() {
7
+ expect(checkIfNonCircularRangesOverlap({
8
+ start: 5,
9
+ end: 100
10
+ }, {
11
+ start: 50,
12
+ end: 50
13
+ })).to.equal(true);
14
+ expect(checkIfNonCircularRangesOverlap({
15
+ start: 5,
16
+ end: 100
17
+ }, {
18
+ start: 50,
19
+ end: 500
20
+ })).to.equal(true);
21
+ expect(checkIfNonCircularRangesOverlap({
22
+ start: 5,
23
+ end: 100
24
+ }, {
25
+ start: 0,
26
+ end: 5
27
+ })).to.equal(true);
28
+ });
29
+ it('returns false if non circular ranges do not overlap', function() {
30
+ expect(checkIfNonCircularRangesOverlap({
31
+ start: 5,
32
+ end: 100
33
+ }, {
34
+ start: 1,
35
+ end: 4
36
+ })).to.equal(false);
37
+ expect(checkIfNonCircularRangesOverlap({
38
+ start: 5,
39
+ end: 100
40
+ }, {
41
+ start: 101,
42
+ end: 101
43
+ })).to.equal(false);
44
+ });
45
+ });
@@ -0,0 +1,16 @@
1
+ //
2
+ import checkIfNonCircularRangesOverlap from './checkIfNonCircularRangesOverlap';
3
+
4
+ import splitRangeIntoTwoPartsIfItIsCircular from './splitRangeIntoTwoPartsIfItIsCircular';
5
+ // ac.throw([ac.posInt, ac.posInt, ac.bool], arguments);
6
+
7
+ export default function checkIfPotentiallyCircularRangesOverlap(range, comparisonRange) {
8
+ // ac.throw([ac.range, ac.range], arguments);
9
+ //split the potentially circular ranges and compare each part for overlap
10
+ return splitRangeIntoTwoPartsIfItIsCircular(range, Infinity).some(function (splitRange) {
11
+ return splitRangeIntoTwoPartsIfItIsCircular(comparisonRange, Infinity).some(function (splitComparisonRange) {
12
+ return checkIfNonCircularRangesOverlap(splitRange, splitComparisonRange);
13
+ })
14
+ })
15
+ };
16
+
@@ -0,0 +1,73 @@
1
+ import {expect} from 'chai';
2
+
3
+ import checkIfPotentiallyCircularRangesOverlap from './checkIfPotentiallyCircularRangesOverlap.js';
4
+ // checkIfPotentiallyCircularRangesOverlap(frame, sequence, minimumOrfSize, forward, circular)
5
+ describe('checkIfPotentiallyCircularRangesOverlap', function() {
6
+ it('returns true if ranges do overlap', function() {
7
+ expect(checkIfPotentiallyCircularRangesOverlap({
8
+ start: 5,
9
+ end: 100
10
+ }, {
11
+ start: 50,
12
+ end: 50
13
+ })).to.equal(true);
14
+ expect(checkIfPotentiallyCircularRangesOverlap({
15
+ start: 5,
16
+ end: 100
17
+ }, {
18
+ start: 50,
19
+ end: 500
20
+ })).to.equal(true);
21
+ expect(checkIfPotentiallyCircularRangesOverlap({
22
+ start: 5,
23
+ end: 100
24
+ }, {
25
+ start: 0,
26
+ end: 5
27
+ })).to.equal(true);
28
+ expect(checkIfPotentiallyCircularRangesOverlap({
29
+ start: 50,
30
+ end: 10
31
+ }, {
32
+ start: 0,
33
+ end: 5
34
+ })).to.equal(true);
35
+ expect(checkIfPotentiallyCircularRangesOverlap({
36
+ start: 50,
37
+ end: 10
38
+ }, {
39
+ start: 20,
40
+ end: 5
41
+ })).to.equal(true);
42
+ expect(checkIfPotentiallyCircularRangesOverlap({
43
+ start: 50,
44
+ end: 10
45
+ }, {
46
+ start: 20,
47
+ end: 51
48
+ })).to.equal(true);
49
+ });
50
+ it('returns false if ranges do not overlap', function() {
51
+ expect(checkIfPotentiallyCircularRangesOverlap({
52
+ start: 5,
53
+ end: 100
54
+ }, {
55
+ start: 1,
56
+ end: 4
57
+ })).to.equal(false);
58
+ expect(checkIfPotentiallyCircularRangesOverlap({
59
+ start: 50,
60
+ end: 10
61
+ }, {
62
+ start: 20,
63
+ end: 49
64
+ })).to.equal(false);
65
+ expect(checkIfPotentiallyCircularRangesOverlap({
66
+ start: 5,
67
+ end: 100
68
+ }, {
69
+ start: 101,
70
+ end: 101
71
+ })).to.equal(false);
72
+ });
73
+ });
@@ -0,0 +1,47 @@
1
+
2
+
3
+ //this function is a little confusing, but basically it takes an array of overlaps
4
+ //generated from a range overlaps calculation, and it sews them together if possible
5
+ export default function collapseOverlapsGeneratedFromRangeComparisonIfPossible(overlaps, sequenceLength, optionalOriginalRange) {
6
+ const originalRangeLinear = optionalOriginalRange && (optionalOriginalRange.start <= optionalOriginalRange.end)
7
+ if (overlaps.length === 1 || overlaps.length === 0) {
8
+ return overlaps;
9
+ } else if (overlaps.length === 2) {
10
+ if (overlaps[0].start === 0 && overlaps[1].end + 1 === sequenceLength && !originalRangeLinear) {
11
+ return [{
12
+ start: overlaps[1].start,
13
+ end: overlaps[0].end
14
+ }];
15
+ } else if (overlaps[1].start === 0 && overlaps[0].end + 1 === sequenceLength && !originalRangeLinear) {
16
+ return [{
17
+ start: overlaps[0].start,
18
+ end: overlaps[1].end
19
+ }];
20
+ } else {
21
+ return overlaps;
22
+ }
23
+ } else if (overlaps.length === 3) {
24
+ const firstOverlap = overlaps[0];
25
+ const secondOverlap = overlaps[1];
26
+ const thirdOverlap = overlaps[2];
27
+ let collapsedOverlaps = collapseOverlapsGeneratedFromRangeComparisonIfPossible([firstOverlap, secondOverlap], sequenceLength, optionalOriginalRange);
28
+ if (collapsedOverlaps.length === 1) {
29
+ collapsedOverlaps.push(thirdOverlap);
30
+ return collapsedOverlaps;
31
+ } else {
32
+ collapsedOverlaps = collapseOverlapsGeneratedFromRangeComparisonIfPossible([firstOverlap, thirdOverlap], sequenceLength, optionalOriginalRange);
33
+ if (collapsedOverlaps.length === 1) {
34
+ collapsedOverlaps.push(secondOverlap);
35
+ return collapsedOverlaps;
36
+ } else {
37
+ collapsedOverlaps = collapseOverlapsGeneratedFromRangeComparisonIfPossible([secondOverlap, thirdOverlap], sequenceLength, optionalOriginalRange);
38
+ if (collapsedOverlaps.length === 1) {
39
+ collapsedOverlaps.push(firstOverlap);
40
+ return collapsedOverlaps;
41
+ } else {
42
+ return overlaps;
43
+ }
44
+ }
45
+ }
46
+ }
47
+ };