@teselagen/sequence-utils 0.3.41 → 0.3.42-beta.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 (237) hide show
  1. package/DNAComplementMap.d.ts +1 -1
  2. package/README.md +2 -8
  3. package/addGapsToSeqReads.d.ts +16 -3
  4. package/adjustAnnotationsToInsert.d.ts +2 -1
  5. package/adjustBpsToReplaceOrInsert.d.ts +2 -1
  6. package/aliasedEnzymesByName.d.ts +37 -1
  7. package/aminoAcidToDegenerateDnaMap.d.ts +1 -31
  8. package/aminoAcidToDegenerateRnaMap.d.ts +1 -1
  9. package/annotateSingleSeq.d.ts +5 -4
  10. package/annotationTypes.d.ts +2 -2
  11. package/autoAnnotate.d.ts +17 -8
  12. package/bioData.d.ts +10 -58
  13. package/calculateEndStability.d.ts +1 -1
  14. package/calculateNebTa.d.ts +6 -1
  15. package/calculateNebTm.d.ts +6 -4
  16. package/calculatePercentGC.d.ts +1 -1
  17. package/calculateSantaLuciaTm.d.ts +28 -114
  18. package/calculateTm.d.ts +13 -1
  19. package/computeDigestFragments.d.ts +30 -24
  20. package/condensePairwiseAlignmentDifferences.d.ts +1 -1
  21. package/convertAACaretPositionOrRangeToDna.d.ts +2 -1
  22. package/convertDnaCaretPositionOrRangeToAA.d.ts +2 -1
  23. package/cutSequenceByRestrictionEnzyme.d.ts +2 -1
  24. package/defaultEnzymesByName.d.ts +2 -1
  25. package/degenerateDnaToAminoAcidMap.d.ts +1 -1
  26. package/degenerateRnaToAminoAcidMap.d.ts +1 -1
  27. package/deleteSequenceDataAtRange.d.ts +2 -1
  28. package/diffUtils.d.ts +9 -7
  29. package/doesEnzymeChopOutsideOfRecognitionSite.d.ts +2 -1
  30. package/featureTypesAndColors.d.ts +19 -6
  31. package/filterSequenceString.d.ts +14 -10
  32. package/findApproxMatches.d.ts +7 -1
  33. package/findNearestRangeOfSequenceOverlapToPosition.d.ts +2 -1
  34. package/findOrfsInPlasmid.d.ts +2 -11
  35. package/findSequenceMatches.d.ts +11 -1
  36. package/generateAnnotations.d.ts +2 -1
  37. package/generateSequenceData.d.ts +8 -13
  38. package/getAllInsertionsInSeqReads.d.ts +11 -1
  39. package/getAminoAcidDataForEachBaseOfDna.d.ts +6 -5
  40. package/getAminoAcidFromSequenceTriplet.d.ts +1 -1
  41. package/getAminoAcidStringFromSequenceString.d.ts +3 -1
  42. package/getCodonRangeForAASliver.d.ts +3 -4
  43. package/getComplementAminoAcidStringFromSequenceString.d.ts +1 -1
  44. package/getComplementSequenceAndAnnotations.d.ts +5 -1
  45. package/getComplementSequenceString.d.ts +1 -1
  46. package/getCutsiteType.d.ts +2 -1
  47. package/getCutsitesFromSequence.d.ts +2 -1
  48. package/getDegenerateDnaStringFromAAString.d.ts +1 -1
  49. package/getDegenerateRnaStringFromAAString.d.ts +1 -1
  50. package/getDigestFragmentsForCutsites.d.ts +4 -1
  51. package/getDigestFragmentsForRestrictionEnzymes.d.ts +8 -1
  52. package/getInsertBetweenVals.d.ts +2 -1
  53. package/getLeftAndRightOfSequenceInRangeGivenPosition.d.ts +2 -1
  54. package/getOrfsFromSequence.d.ts +17 -11
  55. package/getOverlapBetweenTwoSequences.d.ts +2 -1
  56. package/getPossiblePartsFromSequenceAndEnzymes.d.ts +18 -1
  57. package/getReverseAminoAcidStringFromSequenceString.d.ts +1 -1
  58. package/getReverseComplementAminoAcidStringFromSequenceString.d.ts +1 -1
  59. package/getReverseComplementAnnotation.d.ts +11 -1
  60. package/getReverseComplementSequenceAndAnnotations.d.ts +5 -1
  61. package/getReverseComplementSequenceString.d.ts +1 -1
  62. package/getReverseSequenceString.d.ts +1 -1
  63. package/getSequenceDataBetweenRange.d.ts +9 -1
  64. package/getVirtualDigest.d.ts +11 -10
  65. package/guessIfSequenceIsDnaAndNotProtein.d.ts +5 -1
  66. package/index.cjs +762 -495
  67. package/index.d.ts +9 -5
  68. package/index.js +763 -496
  69. package/index.umd.cjs +762 -495
  70. package/insertGapsIntoRefSeq.d.ts +2 -1
  71. package/insertSequenceDataAtPositionOrRange.d.ts +10 -1
  72. package/isEnzymeType2S.d.ts +2 -1
  73. package/mapAnnotationsToRows.d.ts +9 -1
  74. package/package.json +9 -6
  75. package/prepareCircularViewData.d.ts +2 -1
  76. package/prepareRowData.d.ts +7 -3
  77. package/proteinAlphabet.d.ts +1 -1
  78. package/rotateBpsToPosition.d.ts +1 -1
  79. package/rotateSequenceDataToPosition.d.ts +3 -1
  80. package/shiftAnnotationsByLen.d.ts +4 -3
  81. package/src/{addGapsToSeqReads.js → addGapsToSeqReads.ts} +33 -14
  82. package/src/{adjustAnnotationsToInsert.js → adjustAnnotationsToInsert.ts} +6 -5
  83. package/src/{adjustBpsToReplaceOrInsert.js → adjustBpsToReplaceOrInsert.ts} +31 -8
  84. package/src/{aliasedEnzymesByName.js → aliasedEnzymesByName.ts} +4 -1
  85. package/src/{aminoAcidToDegenerateDnaMap.js → aminoAcidToDegenerateDnaMap.ts} +1 -1
  86. package/src/{annotateSingleSeq.js → annotateSingleSeq.ts} +11 -3
  87. package/src/autoAnnotate.test.js +0 -1
  88. package/src/{autoAnnotate.js → autoAnnotate.ts} +69 -24
  89. package/src/{bioData.js → bioData.ts} +2 -2
  90. package/src/{calculateEndStability.js → calculateEndStability.ts} +21 -16
  91. package/src/{calculateNebTa.js → calculateNebTa.ts} +20 -8
  92. package/src/{calculateNebTm.js → calculateNebTm.ts} +15 -9
  93. package/src/{calculatePercentGC.js → calculatePercentGC.ts} +1 -1
  94. package/src/{calculateSantaLuciaTm.js → calculateSantaLuciaTm.ts} +29 -22
  95. package/src/{calculateTm.js → calculateTm.ts} +50 -59
  96. package/src/{computeDigestFragments.js → computeDigestFragments.ts} +92 -36
  97. package/src/{condensePairwiseAlignmentDifferences.js → condensePairwiseAlignmentDifferences.ts} +4 -4
  98. package/src/{convertAACaretPositionOrRangeToDna.js → convertAACaretPositionOrRangeToDna.ts} +8 -4
  99. package/src/{convertDnaCaretPositionOrRangeToAA.js → convertDnaCaretPositionOrRangeToAA.ts} +8 -4
  100. package/src/cutSequenceByRestrictionEnzyme.ts +345 -0
  101. package/src/{defaultEnzymesByName.js → defaultEnzymesByName.ts} +2 -1
  102. package/src/deleteSequenceDataAtRange.ts +13 -0
  103. package/src/diffUtils.ts +80 -0
  104. package/src/doesEnzymeChopOutsideOfRecognitionSite.ts +16 -0
  105. package/src/{featureTypesAndColors.js → featureTypesAndColors.ts} +29 -14
  106. package/src/{filterSequenceString.js → filterSequenceString.ts} +51 -21
  107. package/src/{findApproxMatches.js → findApproxMatches.ts} +14 -6
  108. package/src/{findNearestRangeOfSequenceOverlapToPosition.js → findNearestRangeOfSequenceOverlapToPosition.ts} +13 -9
  109. package/src/{findOrfsInPlasmid.js → findOrfsInPlasmid.ts} +8 -7
  110. package/src/{findSequenceMatches.js → findSequenceMatches.ts} +31 -13
  111. package/src/{generateAnnotations.js → generateAnnotations.ts} +14 -9
  112. package/src/{generateSequenceData.js → generateSequenceData.ts} +19 -13
  113. package/src/{getAllInsertionsInSeqReads.js → getAllInsertionsInSeqReads.ts} +19 -2
  114. package/src/{getAminoAcidDataForEachBaseOfDna.js → getAminoAcidDataForEachBaseOfDna.ts} +36 -30
  115. package/src/{getAminoAcidFromSequenceTriplet.js → getAminoAcidFromSequenceTriplet.ts} +9 -4
  116. package/src/{getAminoAcidStringFromSequenceString.js → getAminoAcidStringFromSequenceString.ts} +14 -7
  117. package/src/{getCodonRangeForAASliver.js → getCodonRangeForAASliver.ts} +16 -6
  118. package/src/{getComplementAminoAcidStringFromSequenceString.js → getComplementAminoAcidStringFromSequenceString.ts} +5 -3
  119. package/src/{getComplementSequenceAndAnnotations.js → getComplementSequenceAndAnnotations.ts} +8 -6
  120. package/src/{getComplementSequenceString.js → getComplementSequenceString.ts} +5 -2
  121. package/src/getCutsiteType.ts +18 -0
  122. package/src/getCutsitesFromSequence.ts +22 -0
  123. package/src/getDegenerateDnaStringFromAAString.ts +15 -0
  124. package/src/getDegenerateRnaStringFromAAString.ts +15 -0
  125. package/src/{getDigestFragmentsForCutsites.js → getDigestFragmentsForCutsites.ts} +32 -14
  126. package/src/getDigestFragmentsForRestrictionEnzymes.ts +50 -0
  127. package/src/{getInsertBetweenVals.js → getInsertBetweenVals.ts} +8 -5
  128. package/src/{getLeftAndRightOfSequenceInRangeGivenPosition.js → getLeftAndRightOfSequenceInRangeGivenPosition.ts} +11 -10
  129. package/src/{getMassOfAaString.js → getMassOfAaString.ts} +4 -2
  130. package/src/{getOrfsFromSequence.js → getOrfsFromSequence.ts} +27 -7
  131. package/src/{getOverlapBetweenTwoSequences.js → getOverlapBetweenTwoSequences.ts} +4 -4
  132. package/src/{getPossiblePartsFromSequenceAndEnzymes.js → getPossiblePartsFromSequenceAndEnzymes.ts} +52 -25
  133. package/src/{getReverseAminoAcidStringFromSequenceString.js → getReverseAminoAcidStringFromSequenceString.ts} +4 -2
  134. package/src/{getReverseComplementAminoAcidStringFromSequenceString.js → getReverseComplementAminoAcidStringFromSequenceString.ts} +2 -2
  135. package/src/{getReverseComplementAnnotation.js → getReverseComplementAnnotation.ts} +4 -2
  136. package/src/getReverseComplementSequenceAndAnnotations.ts +45 -0
  137. package/src/{getReverseComplementSequenceString.js → getReverseComplementSequenceString.ts} +4 -4
  138. package/src/{getReverseSequenceString.js → getReverseSequenceString.ts} +1 -1
  139. package/src/getSequenceDataBetweenRange.test.js +6 -3
  140. package/src/{getSequenceDataBetweenRange.js → getSequenceDataBetweenRange.ts} +44 -29
  141. package/src/{getVirtualDigest.js → getVirtualDigest.ts} +20 -9
  142. package/src/{guessIfSequenceIsDnaAndNotProtein.js → guessIfSequenceIsDnaAndNotProtein.ts} +11 -5
  143. package/src/{index.test.js → index.test.ts} +9 -5
  144. package/src/{index.js → index.ts} +1 -0
  145. package/src/{insertGapsIntoRefSeq.js → insertGapsIntoRefSeq.ts} +7 -2
  146. package/src/{insertSequenceDataAtPositionOrRange.js → insertSequenceDataAtPositionOrRange.ts} +130 -56
  147. package/src/isEnzymeType2S.ts +5 -0
  148. package/src/mapAnnotationsToRows.ts +256 -0
  149. package/src/prepareCircularViewData.ts +24 -0
  150. package/src/{prepareRowData.js → prepareRowData.ts} +27 -8
  151. package/src/prepareRowData_output1.json +1 -0
  152. package/src/rotateBpsToPosition.ts +12 -0
  153. package/src/{rotateSequenceDataToPosition.js → rotateSequenceDataToPosition.ts} +11 -8
  154. package/src/{shiftAnnotationsByLen.js → shiftAnnotationsByLen.ts} +12 -5
  155. package/src/{threeLetterSequenceStringToAminoAcidMap.js → threeLetterSequenceStringToAminoAcidMap.ts} +29 -9
  156. package/src/{tidyUpAnnotation.js → tidyUpAnnotation.ts} +40 -18
  157. package/src/{tidyUpSequenceData.js → tidyUpSequenceData.ts} +83 -39
  158. package/src/types.ts +98 -0
  159. package/threeLetterSequenceStringToAminoAcidMap.d.ts +11 -921
  160. package/tidyUpAnnotation.d.ts +13 -11
  161. package/tidyUpSequenceData.d.ts +18 -1
  162. package/types.d.ts +96 -0
  163. package/addGapsToSeqReads.test.d.ts +0 -1
  164. package/adjustBpsToReplaceOrInsert.test.d.ts +0 -1
  165. package/aminoAcidToDnaRna.test.d.ts +0 -1
  166. package/annotateSingleSeq.test.d.ts +0 -1
  167. package/autoAnnotate.test.d.ts +0 -1
  168. package/calculateEndStability.test.d.ts +0 -1
  169. package/calculateNebTa.test.d.ts +0 -1
  170. package/calculateNebTm.test.d.ts +0 -1
  171. package/calculatePercentGC.test.d.ts +0 -1
  172. package/calculateSantaLuciaTm.test.d.ts +0 -1
  173. package/calculateTm.test.d.ts +0 -1
  174. package/computeDigestFragments.test.d.ts +0 -1
  175. package/condensePairwiseAlignmentDifferences.test.d.ts +0 -1
  176. package/convertAACaretPositionOrRangeToDna.test.d.ts +0 -1
  177. package/convertDnaCaretPositionOrRangeToAA.test.d.ts +0 -1
  178. package/cutSequenceByRestrictionEnzyme.test.d.ts +0 -1
  179. package/deleteSequenceDataAtRange.test.d.ts +0 -1
  180. package/diffUtils.test.d.ts +0 -1
  181. package/doesEnzymeChopOutsideOfRecognitionSite.test.d.ts +0 -1
  182. package/featureTypesAndColors.test.d.ts +0 -1
  183. package/filterSequenceString.test.d.ts +0 -1
  184. package/findApproxMatches.test.d.ts +0 -1
  185. package/findNearestRangeOfSequenceOverlapToPosition.test.d.ts +0 -1
  186. package/findSequenceMatches.test.d.ts +0 -1
  187. package/generateSequenceData.test.d.ts +0 -1
  188. package/getAllInsertionsInSeqReads.test.d.ts +0 -1
  189. package/getAminoAcidDataForEachBaseOfDna.test.d.ts +0 -1
  190. package/getAminoAcidStringFromSequenceString.test.d.ts +0 -1
  191. package/getComplementSequenceString.test.d.ts +0 -1
  192. package/getDigestFragmentsForRestrictionEnzymes.test.d.ts +0 -1
  193. package/getInsertBetweenVals.test.d.ts +0 -1
  194. package/getLeftAndRightOfSequenceInRangeGivenPosition.test.d.ts +0 -1
  195. package/getMassofAaString.test.d.ts +0 -1
  196. package/getOrfsFromSequence.test.d.ts +0 -1
  197. package/getOverlapBetweenTwoSequences.test.d.ts +0 -1
  198. package/getPossiblePartsFromSequenceAndEnzymes.test.d.ts +0 -1
  199. package/getReverseAminoAcidStringFromSequenceString.test.d.ts +0 -1
  200. package/getReverseComplementAnnotation.test.d.ts +0 -1
  201. package/getReverseComplementSequenceAndAnnotations.test.d.ts +0 -1
  202. package/getReverseComplementSequenceString.test.d.ts +0 -1
  203. package/getReverseSequenceString.test.d.ts +0 -1
  204. package/getSequenceDataBetweenRange.test.d.ts +0 -1
  205. package/getVirtualDigest.test.d.ts +0 -1
  206. package/guessIfSequenceIsDnaAndNotProtein.test.d.ts +0 -1
  207. package/index.test.d.ts +0 -1
  208. package/insertGapsIntoRefSeq.test.d.ts +0 -1
  209. package/insertSequenceDataAtPosition.test.d.ts +0 -1
  210. package/insertSequenceDataAtPositionOrRange.test.d.ts +0 -1
  211. package/mapAnnotationsToRows.test.d.ts +0 -1
  212. package/prepareCircularViewData.test.d.ts +0 -1
  213. package/prepareRowData.test.d.ts +0 -1
  214. package/rotateBpsToPosition.test.d.ts +0 -1
  215. package/rotateSequenceDataToPosition.test.d.ts +0 -1
  216. package/src/cutSequenceByRestrictionEnzyme.js +0 -301
  217. package/src/deleteSequenceDataAtRange.js +0 -5
  218. package/src/diffUtils.js +0 -63
  219. package/src/doesEnzymeChopOutsideOfRecognitionSite.js +0 -10
  220. package/src/getCutsiteType.js +0 -10
  221. package/src/getCutsitesFromSequence.js +0 -17
  222. package/src/getDegenerateDnaStringFromAAString.js +0 -8
  223. package/src/getDegenerateRnaStringFromAAString.js +0 -8
  224. package/src/getDigestFragmentsForRestrictionEnzymes.js +0 -27
  225. package/src/getReverseComplementSequenceAndAnnotations.js +0 -40
  226. package/src/isEnzymeType2S.js +0 -3
  227. package/src/mapAnnotationsToRows.js +0 -174
  228. package/src/prepareCircularViewData.js +0 -17
  229. package/src/rotateBpsToPosition.js +0 -9
  230. package/tidyUpSequenceData.test.d.ts +0 -1
  231. /package/src/{DNAComplementMap.js → DNAComplementMap.ts} +0 -0
  232. /package/src/{aminoAcidToDegenerateRnaMap.js → aminoAcidToDegenerateRnaMap.ts} +0 -0
  233. /package/src/{annotationTypes.js → annotationTypes.ts} +0 -0
  234. /package/src/{degenerateDnaToAminoAcidMap.js → degenerateDnaToAminoAcidMap.ts} +0 -0
  235. /package/src/{degenerateRnaToAminoAcidMap.js → degenerateRnaToAminoAcidMap.ts} +0 -0
  236. /package/src/{insertSequenceDataAtPosition.js → insertSequenceDataAtPosition.ts} +0 -0
  237. /package/src/{proteinAlphabet.js → proteinAlphabet.ts} +0 -0
@@ -1,4 +1,4 @@
1
- import { getRangeLength } from "@teselagen/range-utils";
1
+ import { getRangeLength, Range } from "@teselagen/range-utils";
2
2
  import { map, cloneDeep } from "lodash-es";
3
3
  import convertDnaCaretPositionOrRangeToAa from "./convertDnaCaretPositionOrRangeToAA";
4
4
  import rotateSequenceDataToPosition from "./rotateSequenceDataToPosition";
@@ -7,13 +7,21 @@ import tidyUpSequenceData from "./tidyUpSequenceData";
7
7
  import { modifiableTypes } from "./annotationTypes";
8
8
  import adjustBpsToReplaceOrInsert from "./adjustBpsToReplaceOrInsert";
9
9
  import adjustAnnotationsToInsert from "./adjustAnnotationsToInsert";
10
+ import { Annotation, ChromatogramData, SequenceData } from "./types";
11
+
12
+ interface InsertSequenceDataOptions {
13
+ maintainOriginSplit?: boolean;
14
+ doNotRemoveInvalidChars?: boolean;
15
+ topLevelSeqData?: SequenceData;
16
+ [key: string]: unknown;
17
+ }
10
18
 
11
19
  export default function insertSequenceDataAtPositionOrRange(
12
- _sequenceDataToInsert,
13
- _existingSequenceData,
14
- caretPositionOrRange,
15
- options = {}
16
- ) {
20
+ _sequenceDataToInsert: SequenceData,
21
+ _existingSequenceData: SequenceData,
22
+ caretPositionOrRange: number | Range,
23
+ options: InsertSequenceDataOptions = {}
24
+ ): SequenceData {
17
25
  //maintainOriginSplit means that if you're inserting around the origin with n bps selected before the origin
18
26
  //when inserting new seq, n bps of the new seq should go in before the origin and the rest should be
19
27
  //inserted at the sequence start
@@ -31,13 +39,21 @@ export default function insertSequenceDataAtPositionOrRange(
31
39
  sequenceDataToInsert.isProtein && sequenceDataToInsert.proteinSequence
32
40
  ? sequenceDataToInsert.proteinSequence.length * 3
33
41
  : sequenceDataToInsert.sequence.length;
34
- let caretPosition = caretPositionOrRange;
42
+ let caretPosition =
43
+ typeof caretPositionOrRange === "number"
44
+ ? caretPositionOrRange
45
+ : caretPositionOrRange.start;
35
46
 
36
47
  const isInsertSameLengthAsSelection =
48
+ typeof caretPositionOrRange !== "number" &&
37
49
  sequenceDataToInsert.sequence.length ===
38
- getRangeLength(caretPositionOrRange, existingSequenceData.sequence.length);
50
+ getRangeLength(
51
+ caretPositionOrRange,
52
+ existingSequenceData.sequence.length
53
+ );
39
54
 
40
55
  if (
56
+ typeof caretPositionOrRange !== "number" &&
41
57
  caretPositionOrRange.start > -1 &&
42
58
  getRangeLength(
43
59
  caretPositionOrRange,
@@ -45,12 +61,18 @@ export default function insertSequenceDataAtPositionOrRange(
45
61
  ) === existingSequenceData.sequence.length
46
62
  ) {
47
63
  //handle the case where we're deleting everything!
64
+ const emptyAnnotations = modifiableTypes.reduce(
65
+ (acc, type) => {
66
+ acc[type] = [];
67
+ return acc;
68
+ },
69
+ {} as Record<string, Annotation[]>
70
+ );
71
+
48
72
  existingSequenceData = tidyUpSequenceData(
49
73
  {
50
74
  ...existingSequenceData,
51
- ...modifiableTypes.reduce((acc, type) => {
52
- return (acc[type] = []);
53
- }, {}),
75
+ ...emptyAnnotations,
54
76
  sequence: "",
55
77
  doNotRemoveInvalidChars: true,
56
78
  proteinSequence: "",
@@ -64,7 +86,10 @@ export default function insertSequenceDataAtPositionOrRange(
64
86
  newSequenceData.chromatogramData.baseTraces
65
87
  ) {
66
88
  //handle chromatogramData updates
67
- if (caretPositionOrRange && caretPositionOrRange.start > -1) {
89
+ if (
90
+ typeof caretPositionOrRange !== "number" &&
91
+ caretPositionOrRange.start > -1
92
+ ) {
68
93
  if (caretPositionOrRange.start > caretPositionOrRange.end) {
69
94
  newSequenceData.chromatogramData = trimChromatogram({
70
95
  chromatogramData: newSequenceData.chromatogramData,
@@ -74,14 +99,16 @@ export default function insertSequenceDataAtPositionOrRange(
74
99
  },
75
100
  justBaseCalls: isInsertSameLengthAsSelection
76
101
  });
77
- newSequenceData.chromatogramData = trimChromatogram({
78
- chromatogramData: newSequenceData.chromatogramData,
79
- range: {
80
- start: 0,
81
- end: caretPositionOrRange.end
82
- },
83
- justBaseCalls: isInsertSameLengthAsSelection
84
- });
102
+ if (newSequenceData.chromatogramData) {
103
+ newSequenceData.chromatogramData = trimChromatogram({
104
+ chromatogramData: newSequenceData.chromatogramData,
105
+ range: {
106
+ start: 0,
107
+ end: caretPositionOrRange.end
108
+ },
109
+ justBaseCalls: isInsertSameLengthAsSelection
110
+ });
111
+ }
85
112
  } else {
86
113
  newSequenceData.chromatogramData = trimChromatogram({
87
114
  chromatogramData: newSequenceData.chromatogramData,
@@ -93,13 +120,14 @@ export default function insertSequenceDataAtPositionOrRange(
93
120
  });
94
121
  }
95
122
  }
96
- if (sequenceDataToInsert.sequence) {
123
+ if (sequenceDataToInsert.sequence && newSequenceData.chromatogramData) {
97
124
  insertIntoChromatogram({
98
125
  chromatogramData: newSequenceData.chromatogramData,
99
126
  caretPosition:
127
+ typeof caretPositionOrRange !== "number" &&
100
128
  caretPositionOrRange.start > -1
101
129
  ? caretPositionOrRange.start
102
- : caretPositionOrRange,
130
+ : (caretPositionOrRange as number),
103
131
  seqToInsert: sequenceDataToInsert.sequence,
104
132
  justBaseCalls: isInsertSameLengthAsSelection
105
133
  });
@@ -114,18 +142,25 @@ export default function insertSequenceDataAtPositionOrRange(
114
142
  );
115
143
  newSequenceData.size = newSequenceData.sequence.length;
116
144
  newSequenceData.proteinSequence = adjustBpsToReplaceOrInsert(
117
- existingSequenceData.proteinSequence,
118
- sequenceDataToInsert.proteinSequence,
145
+ existingSequenceData.proteinSequence || "",
146
+ sequenceDataToInsert.proteinSequence || "",
119
147
  convertDnaCaretPositionOrRangeToAa(caretPositionOrRange)
120
148
  );
121
- newSequenceData.proteinSize = newSequenceData.proteinSequence.length;
149
+ newSequenceData.proteinSize = (newSequenceData.proteinSequence || "").length;
122
150
 
123
151
  //handle the insert
124
152
  modifiableTypes.forEach(annotationType => {
125
- let existingAnnotations = existingSequenceData[annotationType];
153
+ let existingAnnotations = existingSequenceData[
154
+ annotationType
155
+ ] as Annotation[];
156
+ if (!existingAnnotations) return;
157
+
126
158
  //update the annotations:
127
159
  //handle the delete if necessary
128
- if (caretPositionOrRange && caretPositionOrRange.start > -1) {
160
+ if (
161
+ typeof caretPositionOrRange !== "number" &&
162
+ caretPositionOrRange.start > -1
163
+ ) {
129
164
  //we have a range! so let's delete it!
130
165
  const range = caretPositionOrRange;
131
166
  caretPosition = range.start > range.end ? 0 : range.start;
@@ -138,25 +173,35 @@ export default function insertSequenceDataAtPositionOrRange(
138
173
  }
139
174
  //first clear the newSequenceData's annotations
140
175
  newSequenceData[annotationType] = [];
176
+ const annotationsToInsert = sequenceDataToInsert[
177
+ annotationType
178
+ ] as Annotation[];
141
179
  //in two steps adjust the annotations to the insert
142
- newSequenceData[annotationType] = newSequenceData[annotationType].concat(
143
- adjustAnnotationsToInsert(
144
- existingAnnotations,
145
- caretPosition,
146
- insertLength
147
- )
148
- );
149
- newSequenceData[annotationType] = newSequenceData[annotationType].concat(
150
- adjustAnnotationsToInsert(
151
- sequenceDataToInsert[annotationType],
152
- 0,
153
- caretPosition
154
- )
155
- );
180
+ if (newSequenceData[annotationType]) {
181
+ // Explicitly cast to unknown array inside concat to avoid TS errors with specific Annotation types if they diverge slightly,
182
+ // though strictly they should be Annotation[]
183
+ (newSequenceData[annotationType] as Annotation[]) = (
184
+ newSequenceData[annotationType] as Annotation[]
185
+ ).concat(
186
+ adjustAnnotationsToInsert(
187
+ existingAnnotations,
188
+ caretPosition,
189
+ insertLength
190
+ )
191
+ );
192
+ if (annotationsToInsert) {
193
+ (newSequenceData[annotationType] as Annotation[]) = (
194
+ newSequenceData[annotationType] as Annotation[]
195
+ ).concat(
196
+ adjustAnnotationsToInsert(annotationsToInsert, 0, caretPosition)
197
+ );
198
+ }
199
+ }
156
200
  });
201
+
157
202
  if (
158
203
  maintainOriginSplit &&
159
- caretPositionOrRange &&
204
+ typeof caretPositionOrRange !== "number" &&
160
205
  caretPositionOrRange.start > caretPositionOrRange.end
161
206
  ) {
162
207
  //we're replacing around the origin and maintainOriginSplit=true
@@ -171,7 +216,11 @@ export default function insertSequenceDataAtPositionOrRange(
171
216
  return newSequenceData;
172
217
  }
173
218
 
174
- function adjustAnnotationsToDelete(annotationsToBeAdjusted, range, maxLength) {
219
+ function adjustAnnotationsToDelete(
220
+ annotationsToBeAdjusted: Annotation[],
221
+ range: Range,
222
+ maxLength: number
223
+ ): Annotation[] {
175
224
  return map(annotationsToBeAdjusted, annotation => {
176
225
  const newRange = adjustRangeToDeletionOfAnotherRange(
177
226
  annotation,
@@ -183,6 +232,10 @@ function adjustAnnotationsToDelete(annotationsToBeAdjusted, range, maxLength) {
183
232
  annotation.locations
184
233
  .map(loc => adjustRangeToDeletionOfAnotherRange(loc, range, maxLength))
185
234
  .filter(range => !!range);
235
+
236
+ // Check if newRange is valid (start/end exist) before returning
237
+ if (!newRange) return null;
238
+
186
239
  if (newLocations && newLocations.length) {
187
240
  return {
188
241
  ...newRange,
@@ -193,7 +246,7 @@ function adjustAnnotationsToDelete(annotationsToBeAdjusted, range, maxLength) {
193
246
  } else {
194
247
  return newRange;
195
248
  }
196
- }).filter(range => !!range); //filter any fully deleted ranges
249
+ }).filter((range): range is Annotation => !!range); //filter any fully deleted ranges
197
250
  }
198
251
 
199
252
  function insertIntoChromatogram({
@@ -201,22 +254,28 @@ function insertIntoChromatogram({
201
254
  caretPosition,
202
255
  seqToInsert,
203
256
  justBaseCalls
204
- }) {
257
+ }: {
258
+ chromatogramData: ChromatogramData;
259
+ caretPosition: number;
260
+ seqToInsert: string;
261
+ justBaseCalls?: boolean;
262
+ }): ChromatogramData | void {
205
263
  if (!seqToInsert.length) return;
206
264
 
207
- chromatogramData.baseCalls &&
208
- chromatogramData.baseCalls.splice(
265
+ if (chromatogramData.baseCalls) {
266
+ (chromatogramData.baseCalls as unknown[]).splice(
209
267
  caretPosition,
210
268
  0,
211
269
  ...seqToInsert.split("")
212
270
  );
271
+ }
213
272
  if (justBaseCalls) {
214
273
  //return early if just base calls
215
274
  return chromatogramData;
216
275
  }
217
276
 
218
- const baseTracesToInsert = [];
219
- const qualNumsToInsert = [];
277
+ const baseTracesToInsert: unknown[] = [];
278
+ const qualNumsToInsert: number[] = [];
220
279
 
221
280
  for (let index = 0; index < seqToInsert.length; index++) {
222
281
  qualNumsToInsert.push(0);
@@ -229,10 +288,20 @@ function insertIntoChromatogram({
229
288
  });
230
289
  }
231
290
 
232
- chromatogramData.baseTraces &&
233
- chromatogramData.baseTraces.splice(caretPosition, 0, ...baseTracesToInsert);
234
- chromatogramData.qualNums &&
235
- chromatogramData.qualNums.splice(caretPosition, 0, ...qualNumsToInsert);
291
+ if (chromatogramData.baseTraces) {
292
+ (chromatogramData.baseTraces as unknown[]).splice(
293
+ caretPosition,
294
+ 0,
295
+ ...baseTracesToInsert
296
+ );
297
+ }
298
+ if (chromatogramData.qualNums) {
299
+ (chromatogramData.qualNums as unknown[]).splice(
300
+ caretPosition,
301
+ 0,
302
+ ...qualNumsToInsert
303
+ );
304
+ }
236
305
 
237
306
  return chromatogramData;
238
307
  }
@@ -241,13 +310,18 @@ function trimChromatogram({
241
310
  chromatogramData,
242
311
  range: { start, end },
243
312
  justBaseCalls
244
- }) {
313
+ }: {
314
+ chromatogramData: ChromatogramData;
315
+ range: { start: number; end: number };
316
+ justBaseCalls?: boolean;
317
+ }): ChromatogramData {
245
318
  [
246
319
  "baseCalls",
247
320
  ...(justBaseCalls ? [] : ["qualNums", "baseTraces", "basePos"])
248
321
  ].forEach(type => {
249
- chromatogramData[type] &&
250
- chromatogramData[type].splice(start, end - start + 1);
322
+ if (chromatogramData[type]) {
323
+ (chromatogramData[type] as unknown[]).splice(start, end - start + 1);
324
+ }
251
325
  });
252
326
 
253
327
  return chromatogramData;
@@ -0,0 +1,5 @@
1
+ import { RestrictionEnzyme } from "./types";
2
+
3
+ export default function isEnzymeType2S(e: RestrictionEnzyme) {
4
+ return e.site.length < e.topSnipOffset || e.site.length < e.bottomSnipOffset;
5
+ }
@@ -0,0 +1,256 @@
1
+ import { each, forEach, startsWith, filter } from "lodash-es";
2
+ import {
3
+ getYOffsetForPotentiallyCircularRange,
4
+ splitRangeIntoTwoPartsIfItIsCircular,
5
+ checkIfPotentiallyCircularRangesOverlap
6
+ } from "@teselagen/range-utils";
7
+ import { Annotation } from "./types";
8
+
9
+ export interface MappedAnnotation extends Annotation {
10
+ yOffset?: number;
11
+ enclosingRangeType?: "beginning" | "end" | "beginningAndEnd";
12
+ annotation?: Annotation;
13
+ }
14
+
15
+ export default function mapAnnotationsToRows(
16
+ annotations: Annotation[],
17
+ sequenceLength: number,
18
+ bpsPerRow: number,
19
+ { splitForwardReverse }: { splitForwardReverse?: boolean } = {}
20
+ ) {
21
+ const annotationsToRowsMap: Record<number | string, MappedAnnotation[]> = {};
22
+ const yOffsetLevelMap: Record<
23
+ string | number,
24
+ { start: number; end: number }[][]
25
+ > = {};
26
+ const wrappedAnnotations: Record<string, boolean> = {};
27
+
28
+ each(annotations, annotation => {
29
+ const containsLocations = !!(
30
+ annotation.locations && annotation.locations.length
31
+ );
32
+ if (annotation.overlapsSelf) {
33
+ if (!wrappedAnnotations[annotation.id as string]) {
34
+ mapAnnotationToRows({
35
+ wrappedAnnotations,
36
+ annotation: {
37
+ ...annotation,
38
+ start: 0,
39
+ end: sequenceLength - 1,
40
+ id: `__tempAnnRemoveMe__${annotation.id}`,
41
+ overlapsSelf: false
42
+ },
43
+ sequenceLength,
44
+ bpsPerRow,
45
+ annotationsToRowsMap,
46
+ yOffsetLevelMap,
47
+ containsLocations,
48
+ splitForwardReverse
49
+ });
50
+ wrappedAnnotations[annotation.id as string] = true;
51
+ }
52
+ }
53
+
54
+ mapAnnotationToRows({
55
+ wrappedAnnotations,
56
+ annotation,
57
+ sequenceLength,
58
+ bpsPerRow,
59
+ annotationsToRowsMap,
60
+ yOffsetLevelMap,
61
+ containsLocations,
62
+ splitForwardReverse
63
+ });
64
+
65
+ if (containsLocations) {
66
+ annotation.locations?.forEach(location => {
67
+ mapAnnotationToRows({
68
+ wrappedAnnotations,
69
+ annotation,
70
+ sequenceLength,
71
+ bpsPerRow,
72
+ annotationsToRowsMap,
73
+ yOffsetLevelMap,
74
+ location: location as Annotation,
75
+ splitForwardReverse
76
+ });
77
+ });
78
+ }
79
+ });
80
+
81
+ forEach(annotationsToRowsMap, (annotationsForRow, i) => {
82
+ annotationsToRowsMap[i] = filter(
83
+ annotationsForRow,
84
+ ann => !startsWith(String(ann.id), "__tempAnnRemoveMe__")
85
+ );
86
+ });
87
+ return annotationsToRowsMap;
88
+ }
89
+
90
+ interface MapAnnotationToRowsParams {
91
+ wrappedAnnotations: Record<string, boolean>;
92
+ annotation: Annotation;
93
+ sequenceLength: number;
94
+ bpsPerRow: number;
95
+ annotationsToRowsMap: Record<number | string, MappedAnnotation[]>;
96
+ yOffsetLevelMap: Record<string | number, { start: number; end: number }[][]>;
97
+ location?: Annotation;
98
+ containsLocations?: boolean;
99
+ splitForwardReverse?: boolean;
100
+ }
101
+
102
+ function mapAnnotationToRows({
103
+ annotation,
104
+ sequenceLength,
105
+ bpsPerRow,
106
+ annotationsToRowsMap,
107
+ yOffsetLevelMap,
108
+ location,
109
+ containsLocations,
110
+ splitForwardReverse
111
+ }: MapAnnotationToRowsParams) {
112
+ const ranges = splitRangeIntoTwoPartsIfItIsCircular(
113
+ location || annotation,
114
+ sequenceLength
115
+ );
116
+
117
+ ranges.forEach((range, index) => {
118
+ const startingRow = Math.floor(range.start / bpsPerRow);
119
+ const endingRow = Math.floor(range.end / bpsPerRow);
120
+
121
+ for (let rowNumber = startingRow; rowNumber <= endingRow; rowNumber++) {
122
+ if (!annotationsToRowsMap[rowNumber]) {
123
+ annotationsToRowsMap[rowNumber] = [];
124
+ }
125
+ const key = splitForwardReverse
126
+ ? annotation.forward
127
+ ? rowNumber + "_forward"
128
+ : rowNumber + "_reverse"
129
+ : rowNumber;
130
+
131
+ const annotationsForRow = annotationsToRowsMap[rowNumber];
132
+ if (!yOffsetLevelMap[key]) {
133
+ yOffsetLevelMap[key] = [];
134
+ }
135
+
136
+ let yOffset: number | undefined;
137
+ const yOffsetsForRow = yOffsetLevelMap[key];
138
+ const start =
139
+ rowNumber === startingRow ? range.start : rowNumber * bpsPerRow;
140
+ const end =
141
+ rowNumber === endingRow
142
+ ? range.end
143
+ : rowNumber * bpsPerRow + bpsPerRow - 1;
144
+
145
+ if (annotation.overlapsSelf) {
146
+ annotationsForRow.forEach(ann => {
147
+ if (ann.id === `__tempAnnRemoveMe__${annotation.id}`) {
148
+ yOffset = ann.yOffset;
149
+ }
150
+ });
151
+ if (yOffset === undefined) {
152
+ annotationsForRow.forEach(ann => {
153
+ if (ann.id === annotation.id) {
154
+ yOffset = ann.yOffset;
155
+ }
156
+ });
157
+ }
158
+ } else {
159
+ if (location) {
160
+ annotationsForRow.forEach(ann => {
161
+ if (ann.id === annotation.id) {
162
+ yOffset = ann.yOffset;
163
+ }
164
+ });
165
+ } else {
166
+ if (
167
+ index > 0 &&
168
+ annotationsForRow.length &&
169
+ annotationsForRow[annotationsForRow.length - 1].annotation ===
170
+ annotation
171
+ ) {
172
+ yOffset = annotationsForRow[annotationsForRow.length - 1].yOffset;
173
+ } else {
174
+ const siblingRangesOnThisRow = ranges.slice(index + 1).filter(r => {
175
+ const rStartRow = Math.floor(r.start / bpsPerRow);
176
+ const rEndRow = Math.floor(r.end / bpsPerRow);
177
+ return rowNumber >= rStartRow && rowNumber <= rEndRow;
178
+ });
179
+
180
+ if (siblingRangesOnThisRow.length > 0) {
181
+ // We have future ranges for this annotation on this row.
182
+ // We must choose a yOffset that works for the current range AND all future ranges.
183
+ let foundYOffset = -1;
184
+ yOffsetsForRow.some((rangesAlreadyAddedToYOffset, levelIndex) => {
185
+ const rangeBlocked = rangesAlreadyAddedToYOffset.some(
186
+ comparisonRange => {
187
+ return checkIfPotentiallyCircularRangesOverlap(
188
+ range,
189
+ comparisonRange
190
+ );
191
+ }
192
+ );
193
+ if (rangeBlocked) return false;
194
+
195
+ // Check siblings
196
+ const siblingBlocked = siblingRangesOnThisRow.some(
197
+ siblingRange => {
198
+ return rangesAlreadyAddedToYOffset.some(comparisonRange => {
199
+ return checkIfPotentiallyCircularRangesOverlap(
200
+ siblingRange,
201
+ comparisonRange
202
+ );
203
+ });
204
+ }
205
+ );
206
+
207
+ if (!siblingBlocked) {
208
+ foundYOffset = levelIndex;
209
+ return true;
210
+ }
211
+ return false;
212
+ });
213
+
214
+ if (foundYOffset > -1) {
215
+ yOffset = foundYOffset;
216
+ yOffsetsForRow[foundYOffset].push(range);
217
+ } else {
218
+ // Create new level
219
+ yOffset = yOffsetsForRow.length;
220
+ yOffsetsForRow.push([range]);
221
+ }
222
+ } else {
223
+ yOffset = getYOffsetForPotentiallyCircularRange(
224
+ range,
225
+ yOffsetsForRow,
226
+ false
227
+ );
228
+ }
229
+ }
230
+ if (yOffset !== undefined) {
231
+ if (!yOffsetsForRow[yOffset]) yOffsetsForRow[yOffset] = [];
232
+ yOffsetsForRow[yOffset].push({
233
+ start: start,
234
+ end: end
235
+ });
236
+ }
237
+ }
238
+ }
239
+
240
+ annotationsForRow.push({
241
+ ...annotation,
242
+ id: annotation.id,
243
+ annotation: annotation,
244
+ start: start,
245
+ end: end,
246
+ ...(containsLocations && { containsLocations }),
247
+ ...(location && { isJoinedLocation: !!location }),
248
+ yOffset: yOffset,
249
+ enclosingRangeType: range.type as
250
+ | "beginning"
251
+ | "end"
252
+ | "beginningAndEnd"
253
+ });
254
+ }
255
+ });
256
+ }
@@ -0,0 +1,24 @@
1
+ import { cloneDeep } from "lodash-es";
2
+ import { getYOffsetsForPotentiallyCircularRanges } from "@teselagen/range-utils";
3
+ import { annotationTypes } from "./annotationTypes";
4
+ import { SequenceData, Annotation } from "./types";
5
+
6
+ //basically just adds yOffsets to the annotations
7
+ export default function prepareCircularViewData(sequenceData: SequenceData) {
8
+ const clonedSeqData = cloneDeep(sequenceData);
9
+ annotationTypes.forEach(annotationType => {
10
+ if (annotationType !== "cutsites") {
11
+ const annotations = clonedSeqData[annotationType] as Annotation[];
12
+ if (annotations) {
13
+ const maxYOffset = getYOffsetsForPotentiallyCircularRanges(
14
+ annotations,
15
+ true
16
+ ).maxYOffset;
17
+ (
18
+ clonedSeqData[annotationType] as Annotation[] & { maxYOffset: number }
19
+ ).maxYOffset = maxYOffset;
20
+ }
21
+ }
22
+ });
23
+ return clonedSeqData;
24
+ }
@@ -1,17 +1,31 @@
1
- // ac.throw([ac.posInt, ac.posInt, ac.bool], arguments);
2
- import mapAnnotationsToRows from "./mapAnnotationsToRows";
1
+ import mapAnnotationsToRows, { MappedAnnotation } from "./mapAnnotationsToRows";
3
2
 
4
3
  import { annotationTypes } from "./annotationTypes";
5
4
 
6
- export default function prepareRowData(sequenceData, bpsPerRow) {
7
- // ac.throw([ac.sequenceData, ac.posInt], arguments);
5
+ import { SequenceData, Annotation } from "./types";
6
+
7
+ export interface RowData {
8
+ rowNumber: number;
9
+ start: number;
10
+ end: number;
11
+ sequence: string;
12
+ [key: string]: MappedAnnotation[] | number | string;
13
+ }
14
+
15
+ export default function prepareRowData(
16
+ sequenceData: SequenceData,
17
+ bpsPerRow: number
18
+ ) {
8
19
  const sequenceLength = sequenceData.sequence.length;
9
20
  const totalRows = Math.ceil(sequenceLength / bpsPerRow) || 1; //this check makes sure there is always at least 1 row!
10
- const rows = [];
11
- const rowMap = {};
21
+ const rows: RowData[] = [];
22
+ const rowMap: Record<
23
+ string,
24
+ Record<string | number, MappedAnnotation[]>
25
+ > = {};
12
26
  annotationTypes.forEach(type => {
13
27
  rowMap[type] = mapAnnotationsToRows(
14
- sequenceData[type],
28
+ (sequenceData[type] as Annotation[]) || [],
15
29
  sequenceLength,
16
30
  bpsPerRow,
17
31
  { splitForwardReverse: type === "primers" }
@@ -19,7 +33,12 @@ export default function prepareRowData(sequenceData, bpsPerRow) {
19
33
  });
20
34
 
21
35
  for (let rowNumber = 0; rowNumber < totalRows; rowNumber++) {
22
- const row = {};
36
+ const row: RowData = {
37
+ rowNumber,
38
+ start: 0,
39
+ end: 0,
40
+ sequence: ""
41
+ };
23
42
  row.rowNumber = rowNumber;
24
43
  row.start = rowNumber * bpsPerRow;
25
44
  row.end =
@@ -138,6 +138,7 @@
138
138
  },
139
139
  "start": 1,
140
140
  "end": 3,
141
+ "forward": true,
141
142
  "yOffset": 0,
142
143
  "enclosingRangeType": "beginningAndEnd"
143
144
  }
@@ -0,0 +1,12 @@
1
+ export default function rotateBpsToPosition(
2
+ bps: string,
3
+ caretPosition: number
4
+ ) {
5
+ return arrayRotate(bps.split(""), caretPosition).join("");
6
+ }
7
+
8
+ function arrayRotate<T>(arr: T[], count: number): T[] {
9
+ count -= arr.length * Math.floor(count / arr.length);
10
+ arr.push(...arr.splice(0, count));
11
+ return arr;
12
+ }