@jbrowse/plugin-alignments 2.16.0 → 2.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (221) hide show
  1. package/dist/AlignmentsFeatureDetail/AlignmentsFeatureDetail.js +2 -3
  2. package/dist/AlignmentsFeatureDetail/Flags.js +2 -2
  3. package/dist/AlignmentsFeatureDetail/LinkedPairedAlignments.js +2 -2
  4. package/dist/AlignmentsFeatureDetail/SupplementaryAlignments.js +2 -2
  5. package/dist/AlignmentsFeatureDetail/getSAFeatures.js +2 -2
  6. package/dist/AlignmentsFeatureDetail/stateModelFactory.d.ts +1 -1
  7. package/dist/BamAdapter/BamAdapter.d.ts +3 -2
  8. package/dist/BamAdapter/BamAdapter.js +34 -11
  9. package/dist/BamAdapter/BamSlightlyLazyFeature.d.ts +3 -17
  10. package/dist/BamAdapter/BamSlightlyLazyFeature.js +42 -72
  11. package/dist/CramAdapter/CramAdapter.d.ts +4 -3
  12. package/dist/CramAdapter/CramAdapter.js +24 -7
  13. package/dist/CramAdapter/CramSlightlyLazyFeature.d.ts +21 -27
  14. package/dist/CramAdapter/CramSlightlyLazyFeature.js +74 -73
  15. package/dist/CramAdapter/util.d.ts +1 -10
  16. package/dist/LinearAlignmentsDisplay/components/AlignmentsDisplay.d.ts +1 -1
  17. package/dist/LinearAlignmentsDisplay/index.js +2 -2
  18. package/dist/LinearAlignmentsDisplay/{models/model.d.ts → model.d.ts} +6 -3
  19. package/dist/LinearAlignmentsDisplay/{models/model.js → model.js} +11 -7
  20. package/dist/LinearPileupDisplay/SharedLinearPileupDisplayMixin.d.ts +6 -27
  21. package/dist/LinearPileupDisplay/SharedLinearPileupDisplayMixin.js +43 -21
  22. package/dist/LinearPileupDisplay/components/ColorByTagDialog.d.ts +5 -4
  23. package/dist/LinearPileupDisplay/components/ColorByTagDialog.js +3 -1
  24. package/dist/LinearPileupDisplay/components/GroupByDialog.js +8 -6
  25. package/dist/LinearPileupDisplay/components/SortByTagDialog.js +6 -4
  26. package/dist/LinearPileupDisplay/model.d.ts +41 -45
  27. package/dist/LinearPileupDisplay/model.js +118 -41
  28. package/dist/LinearReadArcsDisplay/components/ReactComponent.js +1 -1
  29. package/dist/LinearReadArcsDisplay/model.d.ts +22 -21
  30. package/dist/LinearReadArcsDisplay/model.js +13 -14
  31. package/dist/LinearReadCloudDisplay/components/ReactComponent.js +1 -1
  32. package/dist/LinearReadCloudDisplay/model.d.ts +14 -22
  33. package/dist/LinearReadCloudDisplay/model.js +12 -13
  34. package/dist/LinearSNPCoverageDisplay/components/Tooltip.js +49 -19
  35. package/dist/LinearSNPCoverageDisplay/index.js +3 -2
  36. package/dist/LinearSNPCoverageDisplay/{models/model.d.ts → model.d.ts} +3 -13
  37. package/dist/LinearSNPCoverageDisplay/{models/model.js → model.js} +71 -45
  38. package/dist/MismatchParser/cigarToMismatches.d.ts +3 -0
  39. package/dist/MismatchParser/cigarToMismatches.js +94 -0
  40. package/dist/MismatchParser/getNextRefPos.d.ts +4 -0
  41. package/dist/MismatchParser/getNextRefPos.js +40 -0
  42. package/dist/MismatchParser/index.d.ts +4 -29
  43. package/dist/MismatchParser/index.js +10 -321
  44. package/dist/MismatchParser/mdToMismatches.d.ts +3 -0
  45. package/dist/MismatchParser/mdToMismatches.js +80 -0
  46. package/dist/ModificationParser/index.d.ts +19 -0
  47. package/dist/ModificationParser/index.js +144 -0
  48. package/dist/PileupRPC/methods/GetGlobalValueForTag.js +1 -2
  49. package/dist/PileupRPC/methods/GetReducedFeatures.d.ts +1 -1
  50. package/dist/PileupRPC/methods/GetReducedFeatures.js +19 -16
  51. package/dist/PileupRPC/methods/GetVisibleModifications.d.ts +2 -1
  52. package/dist/PileupRPC/methods/GetVisibleModifications.js +9 -6
  53. package/dist/PileupRenderer/PileupLayoutSession.d.ts +8 -7
  54. package/dist/PileupRenderer/PileupRenderer.d.ts +6 -14
  55. package/dist/PileupRenderer/PileupRenderer.js +7 -5
  56. package/dist/PileupRenderer/renderAlignment.js +17 -4
  57. package/dist/PileupRenderer/renderAlignmentShape.js +102 -21
  58. package/dist/PileupRenderer/renderMethylation.d.ts +2 -1
  59. package/dist/PileupRenderer/renderMethylation.js +17 -9
  60. package/dist/PileupRenderer/renderMismatches.js +19 -19
  61. package/dist/PileupRenderer/renderModifications.d.ts +3 -2
  62. package/dist/PileupRenderer/renderModifications.js +31 -34
  63. package/dist/PileupRenderer/renderPerBaseLettering.d.ts +2 -1
  64. package/dist/PileupRenderer/renderPerBaseLettering.js +1 -3
  65. package/dist/PileupRenderer/renderPerBaseQuality.d.ts +2 -1
  66. package/dist/PileupRenderer/renderPerBaseQuality.js +1 -3
  67. package/dist/PileupRenderer/renderSoftClipping.js +6 -6
  68. package/dist/PileupRenderer/sortUtil.d.ts +2 -7
  69. package/dist/PileupRenderer/sortUtil.js +13 -13
  70. package/dist/SNPCoverageAdapter/SNPCoverageAdapter.js +10 -5
  71. package/dist/SNPCoverageAdapter/generateCoverageBins.d.ts +13 -9
  72. package/dist/SNPCoverageAdapter/generateCoverageBins.js +269 -166
  73. package/dist/SNPCoverageRenderer/SNPCoverageRenderer.d.ts +2 -1
  74. package/dist/SNPCoverageRenderer/SNPCoverageRenderer.js +171 -54
  75. package/dist/shared/color.d.ts +0 -10
  76. package/dist/shared/color.js +1 -7
  77. package/{esm/shared → dist/shared/components}/BaseDisplayComponent.d.ts +2 -2
  78. package/{esm/shared → dist/shared/components}/FilterByTagDialog.d.ts +3 -3
  79. package/dist/shared/{FilterByTagDialog.js → components/FilterByTagDialog.js} +5 -1
  80. package/dist/shared/fetchChains.js +1 -2
  81. package/dist/shared/getMaximumModificationAtEachPosition.d.ts +8 -0
  82. package/dist/shared/getMaximumModificationAtEachPosition.js +42 -0
  83. package/dist/shared/getUniqueModifications.d.ts +14 -0
  84. package/dist/shared/getUniqueModifications.js +16 -0
  85. package/dist/shared/getUniqueTags.d.ts +15 -0
  86. package/dist/shared/getUniqueTags.js +18 -0
  87. package/dist/shared/types.d.ts +94 -0
  88. package/dist/shared/util.d.ts +8 -0
  89. package/dist/shared/util.js +26 -0
  90. package/dist/util.d.ts +7 -4
  91. package/dist/util.js +30 -30
  92. package/esm/AlignmentsFeatureDetail/AlignmentsFeatureDetail.js +2 -3
  93. package/esm/AlignmentsFeatureDetail/Flags.js +1 -1
  94. package/esm/AlignmentsFeatureDetail/LinkedPairedAlignments.js +1 -1
  95. package/esm/AlignmentsFeatureDetail/SupplementaryAlignments.js +1 -1
  96. package/esm/AlignmentsFeatureDetail/getSAFeatures.js +2 -2
  97. package/esm/AlignmentsFeatureDetail/stateModelFactory.d.ts +1 -1
  98. package/esm/BamAdapter/BamAdapter.d.ts +3 -2
  99. package/esm/BamAdapter/BamAdapter.js +31 -8
  100. package/esm/BamAdapter/BamSlightlyLazyFeature.d.ts +3 -17
  101. package/esm/BamAdapter/BamSlightlyLazyFeature.js +43 -73
  102. package/esm/CramAdapter/CramAdapter.d.ts +4 -3
  103. package/esm/CramAdapter/CramAdapter.js +22 -5
  104. package/esm/CramAdapter/CramSlightlyLazyFeature.d.ts +21 -27
  105. package/esm/CramAdapter/CramSlightlyLazyFeature.js +74 -73
  106. package/esm/CramAdapter/util.d.ts +1 -10
  107. package/esm/LinearAlignmentsDisplay/components/AlignmentsDisplay.d.ts +1 -1
  108. package/esm/LinearAlignmentsDisplay/index.js +2 -2
  109. package/esm/LinearAlignmentsDisplay/{models/model.d.ts → model.d.ts} +6 -3
  110. package/esm/LinearAlignmentsDisplay/{models/model.js → model.js} +11 -7
  111. package/esm/LinearPileupDisplay/SharedLinearPileupDisplayMixin.d.ts +6 -27
  112. package/esm/LinearPileupDisplay/SharedLinearPileupDisplayMixin.js +45 -23
  113. package/esm/LinearPileupDisplay/components/ColorByTagDialog.d.ts +5 -4
  114. package/esm/LinearPileupDisplay/components/ColorByTagDialog.js +3 -1
  115. package/esm/LinearPileupDisplay/components/GroupByDialog.js +8 -6
  116. package/esm/LinearPileupDisplay/components/SortByTagDialog.js +6 -4
  117. package/esm/LinearPileupDisplay/model.d.ts +41 -45
  118. package/esm/LinearPileupDisplay/model.js +119 -42
  119. package/esm/LinearReadArcsDisplay/components/ReactComponent.js +1 -1
  120. package/esm/LinearReadArcsDisplay/model.d.ts +22 -21
  121. package/esm/LinearReadArcsDisplay/model.js +14 -15
  122. package/esm/LinearReadCloudDisplay/components/ReactComponent.js +1 -1
  123. package/esm/LinearReadCloudDisplay/model.d.ts +14 -22
  124. package/esm/LinearReadCloudDisplay/model.js +13 -14
  125. package/esm/LinearSNPCoverageDisplay/components/Tooltip.js +49 -19
  126. package/esm/LinearSNPCoverageDisplay/index.js +3 -2
  127. package/esm/LinearSNPCoverageDisplay/{models/model.d.ts → model.d.ts} +3 -13
  128. package/esm/LinearSNPCoverageDisplay/{models/model.js → model.js} +72 -46
  129. package/esm/MismatchParser/cigarToMismatches.d.ts +3 -0
  130. package/esm/MismatchParser/cigarToMismatches.js +91 -0
  131. package/esm/MismatchParser/getNextRefPos.d.ts +4 -0
  132. package/esm/MismatchParser/getNextRefPos.js +37 -0
  133. package/esm/MismatchParser/index.d.ts +4 -29
  134. package/esm/MismatchParser/index.js +5 -311
  135. package/esm/MismatchParser/mdToMismatches.d.ts +3 -0
  136. package/esm/MismatchParser/mdToMismatches.js +77 -0
  137. package/esm/ModificationParser/index.d.ts +19 -0
  138. package/esm/ModificationParser/index.js +138 -0
  139. package/esm/PileupRPC/methods/GetGlobalValueForTag.js +1 -2
  140. package/esm/PileupRPC/methods/GetReducedFeatures.d.ts +1 -1
  141. package/esm/PileupRPC/methods/GetReducedFeatures.js +19 -16
  142. package/esm/PileupRPC/methods/GetVisibleModifications.d.ts +2 -1
  143. package/esm/PileupRPC/methods/GetVisibleModifications.js +9 -6
  144. package/esm/PileupRenderer/PileupLayoutSession.d.ts +8 -7
  145. package/esm/PileupRenderer/PileupRenderer.d.ts +6 -14
  146. package/esm/PileupRenderer/PileupRenderer.js +8 -6
  147. package/esm/PileupRenderer/renderAlignment.js +17 -4
  148. package/esm/PileupRenderer/renderAlignmentShape.js +102 -21
  149. package/esm/PileupRenderer/renderMethylation.d.ts +2 -1
  150. package/esm/PileupRenderer/renderMethylation.js +17 -9
  151. package/esm/PileupRenderer/renderMismatches.js +19 -19
  152. package/esm/PileupRenderer/renderModifications.d.ts +3 -2
  153. package/esm/PileupRenderer/renderModifications.js +30 -33
  154. package/esm/PileupRenderer/renderPerBaseLettering.d.ts +2 -1
  155. package/esm/PileupRenderer/renderPerBaseLettering.js +1 -3
  156. package/esm/PileupRenderer/renderPerBaseQuality.d.ts +2 -1
  157. package/esm/PileupRenderer/renderPerBaseQuality.js +1 -3
  158. package/esm/PileupRenderer/renderSoftClipping.js +6 -6
  159. package/esm/PileupRenderer/sortUtil.d.ts +2 -7
  160. package/esm/PileupRenderer/sortUtil.js +13 -13
  161. package/esm/SNPCoverageAdapter/SNPCoverageAdapter.js +10 -5
  162. package/esm/SNPCoverageAdapter/generateCoverageBins.d.ts +13 -9
  163. package/esm/SNPCoverageAdapter/generateCoverageBins.js +269 -166
  164. package/esm/SNPCoverageRenderer/SNPCoverageRenderer.d.ts +2 -1
  165. package/esm/SNPCoverageRenderer/SNPCoverageRenderer.js +171 -54
  166. package/esm/shared/color.d.ts +0 -10
  167. package/esm/shared/color.js +0 -6
  168. package/{dist/shared → esm/shared/components}/BaseDisplayComponent.d.ts +2 -2
  169. package/{dist/shared → esm/shared/components}/FilterByTagDialog.d.ts +3 -3
  170. package/esm/shared/{FilterByTagDialog.js → components/FilterByTagDialog.js} +5 -1
  171. package/esm/shared/fetchChains.js +1 -2
  172. package/esm/shared/getMaximumModificationAtEachPosition.d.ts +8 -0
  173. package/esm/shared/getMaximumModificationAtEachPosition.js +39 -0
  174. package/esm/shared/getUniqueModifications.d.ts +14 -0
  175. package/esm/shared/getUniqueModifications.js +13 -0
  176. package/esm/shared/getUniqueTags.d.ts +15 -0
  177. package/esm/shared/getUniqueTags.js +15 -0
  178. package/esm/shared/types.d.ts +94 -0
  179. package/esm/shared/util.d.ts +8 -0
  180. package/esm/shared/util.js +23 -0
  181. package/esm/util.d.ts +7 -4
  182. package/esm/util.js +28 -27
  183. package/package.json +4 -4
  184. package/dist/LinearPileupDisplay/components/ColorByModificationsDialog.d.ts +0 -15
  185. package/dist/LinearPileupDisplay/components/ColorByModificationsDialog.js +0 -41
  186. package/dist/LinearPileupDisplay/components/ModificationsTable.d.ts +0 -4
  187. package/dist/LinearPileupDisplay/components/ModificationsTable.js +0 -28
  188. package/dist/SNPCoverageAdapter/util.d.ts +0 -25
  189. package/dist/shared/index.d.ts +0 -49
  190. package/dist/shared/index.js +0 -41
  191. package/esm/LinearPileupDisplay/components/ColorByModificationsDialog.d.ts +0 -15
  192. package/esm/LinearPileupDisplay/components/ColorByModificationsDialog.js +0 -36
  193. package/esm/LinearPileupDisplay/components/ModificationsTable.d.ts +0 -4
  194. package/esm/LinearPileupDisplay/components/ModificationsTable.js +0 -22
  195. package/esm/SNPCoverageAdapter/util.d.ts +0 -25
  196. package/esm/shared/index.d.ts +0 -49
  197. package/esm/shared/index.js +0 -36
  198. /package/dist/LinearAlignmentsDisplay/{models/alignmentsModel.d.ts → alignmentsModel.d.ts} +0 -0
  199. /package/dist/LinearAlignmentsDisplay/{models/alignmentsModel.js → alignmentsModel.js} +0 -0
  200. /package/dist/LinearAlignmentsDisplay/{models/configSchema.d.ts → configSchema.d.ts} +0 -0
  201. /package/dist/LinearAlignmentsDisplay/{models/configSchema.js → configSchema.js} +0 -0
  202. /package/dist/LinearAlignmentsDisplay/{models/util.d.ts → util.d.ts} +0 -0
  203. /package/dist/LinearAlignmentsDisplay/{models/util.js → util.js} +0 -0
  204. /package/dist/LinearSNPCoverageDisplay/{models/configSchema.d.ts → configSchema.d.ts} +0 -0
  205. /package/dist/LinearSNPCoverageDisplay/{models/configSchema.js → configSchema.js} +0 -0
  206. /package/dist/shared/{BaseDisplayComponent.js → components/BaseDisplayComponent.js} +0 -0
  207. /package/dist/shared/{renderSvg.d.ts → renderSvgUtil.d.ts} +0 -0
  208. /package/dist/shared/{renderSvg.js → renderSvgUtil.js} +0 -0
  209. /package/dist/{SNPCoverageAdapter/util.js → shared/types.js} +0 -0
  210. /package/esm/LinearAlignmentsDisplay/{models/alignmentsModel.d.ts → alignmentsModel.d.ts} +0 -0
  211. /package/esm/LinearAlignmentsDisplay/{models/alignmentsModel.js → alignmentsModel.js} +0 -0
  212. /package/esm/LinearAlignmentsDisplay/{models/configSchema.d.ts → configSchema.d.ts} +0 -0
  213. /package/esm/LinearAlignmentsDisplay/{models/configSchema.js → configSchema.js} +0 -0
  214. /package/esm/LinearAlignmentsDisplay/{models/util.d.ts → util.d.ts} +0 -0
  215. /package/esm/LinearAlignmentsDisplay/{models/util.js → util.js} +0 -0
  216. /package/esm/LinearSNPCoverageDisplay/{models/configSchema.d.ts → configSchema.d.ts} +0 -0
  217. /package/esm/LinearSNPCoverageDisplay/{models/configSchema.js → configSchema.js} +0 -0
  218. /package/esm/shared/{BaseDisplayComponent.js → components/BaseDisplayComponent.js} +0 -0
  219. /package/esm/shared/{renderSvg.d.ts → renderSvgUtil.d.ts} +0 -0
  220. /package/esm/shared/{renderSvg.js → renderSvgUtil.js} +0 -0
  221. /package/esm/{SNPCoverageAdapter/util.js → shared/types.js} +0 -0
@@ -1,41 +1,15 @@
1
1
  import { Feature } from '@jbrowse/core/util';
2
2
  import type { Buffer } from 'buffer';
3
- export interface Mismatch {
4
- qual?: number;
5
- start: number;
6
- length: number;
7
- type: string;
8
- base: string;
9
- altbase?: string;
10
- seq?: string;
11
- cliplen?: number;
12
- }
3
+ import { Mismatch } from '../shared/types';
13
4
  export declare function parseCigar(cigar?: string): string[];
14
- export declare function cigarToMismatches(ops: string[], seq?: string, ref?: string, qual?: Buffer): Mismatch[];
15
- /**
16
- * parse a SAM MD tag to find mismatching bases of the template versus the
17
- * reference @returns array of mismatches and their positions
18
- */
19
- export declare function mdToMismatches(mdstring: string, ops: string[], cigarMismatches: Mismatch[], seq: string, qual?: Buffer): Mismatch[];
20
- export declare function getMismatches(cigar: string, md?: string, seq?: string, ref?: string, qual?: Buffer): Mismatch[];
21
- export declare function getNextRefPos(cigarOps: string[], positions: number[]): Generator<number, void, unknown>;
22
- export declare function getModificationProbabilities(feature: Feature): number[] | undefined;
23
- export declare function getMethBins(feature: Feature): {
24
- methBins: number[];
25
- methProbs: number[];
26
- };
27
- export declare function getModificationPositions(mm: string, fseq: string, fstrand: number): {
28
- type: string;
29
- positions: number[];
30
- }[];
31
- export declare function getModificationTypes(mm: string): string[];
5
+ export declare function getMismatches(cigar?: string, md?: string, seq?: string, ref?: string, qual?: Buffer): Mismatch[];
32
6
  export declare function getOrientedCigar(flip: boolean, cigar: string[]): string[];
33
7
  export declare function getOrientedMismatches(flip: boolean, cigar: string): Mismatch[];
34
8
  export declare function getLengthOnRef(cigar: string): number;
35
9
  export declare function getLength(cigar: string): number;
36
10
  export declare function getLengthSansClipping(cigar: string): number;
37
11
  export declare function getClip(cigar: string, strand: number): number;
38
- export declare function getTag(f: Feature, tag: string): any;
12
+ export declare function getTag(feature: Feature, tag: string): any;
39
13
  export declare function featurizeSA(SA: string | undefined, id: string, strand: number, readName: string, normalize?: boolean): {
40
14
  refName: string;
41
15
  start: number;
@@ -51,3 +25,4 @@ export declare function featurizeSA(SA: string | undefined, id: string, strand:
51
25
  refName: string;
52
26
  };
53
27
  }[];
28
+ export { getNextRefPos } from './getNextRefPos';
@@ -1,14 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getNextRefPos = void 0;
3
4
  exports.parseCigar = parseCigar;
4
- exports.cigarToMismatches = cigarToMismatches;
5
- exports.mdToMismatches = mdToMismatches;
6
5
  exports.getMismatches = getMismatches;
7
- exports.getNextRefPos = getNextRefPos;
8
- exports.getModificationProbabilities = getModificationProbabilities;
9
- exports.getMethBins = getMethBins;
10
- exports.getModificationPositions = getModificationPositions;
11
- exports.getModificationTypes = getModificationTypes;
12
6
  exports.getOrientedCigar = getOrientedCigar;
13
7
  exports.getOrientedMismatches = getOrientedMismatches;
14
8
  exports.getLengthOnRef = getLengthOnRef;
@@ -17,333 +11,27 @@ exports.getLengthSansClipping = getLengthSansClipping;
17
11
  exports.getClip = getClip;
18
12
  exports.getTag = getTag;
19
13
  exports.featurizeSA = featurizeSA;
20
- const util_1 = require("@jbrowse/core/util");
21
- const util_2 = require("../util");
22
- const mdRegex = new RegExp(/(\d+|\^[a-z]+|[a-z])/gi);
23
- const modificationRegex = new RegExp(/([A-Z])([-+])([^,.?]+)([.?])?/);
14
+ const mdToMismatches_1 = require("./mdToMismatches");
15
+ const cigarToMismatches_1 = require("./cigarToMismatches");
24
16
  const cigarRegex = new RegExp(/([MIDNSHPX=])/);
25
17
  const startClip = new RegExp(/(\d+)[SH]$/);
26
18
  const endClip = new RegExp(/^(\d+)([SH])/);
27
19
  function parseCigar(cigar = '') {
28
20
  return cigar.split(cigarRegex).slice(0, -1);
29
21
  }
30
- function cigarToMismatches(ops, seq, ref, qual) {
31
- let roffset = 0; // reference offset
32
- let soffset = 0; // seq offset
33
- const mismatches = [];
34
- const hasRefAndSeq = ref && seq;
35
- for (let i = 0; i < ops.length; i += 2) {
36
- const len = +ops[i];
37
- const op = ops[i + 1];
38
- if (op === 'M' || op === '=' || op === 'E') {
39
- if (hasRefAndSeq) {
40
- for (let j = 0; j < len; j++) {
41
- if (
42
- // @ts-ignore in the full yarn build of the repo, this says that object is possibly undefined for some reason, ignored
43
- seq[soffset + j].toUpperCase() !== ref[roffset + j].toUpperCase()) {
44
- mismatches.push({
45
- start: roffset + j,
46
- type: 'mismatch',
47
- base: seq[soffset + j],
48
- altbase: ref[roffset + j],
49
- length: 1,
50
- });
51
- }
52
- }
53
- }
54
- soffset += len;
55
- }
56
- if (op === 'I') {
57
- mismatches.push({
58
- start: roffset,
59
- type: 'insertion',
60
- base: `${len}`,
61
- length: 0,
62
- });
63
- soffset += len;
64
- }
65
- else if (op === 'D') {
66
- mismatches.push({
67
- start: roffset,
68
- type: 'deletion',
69
- base: '*',
70
- length: len,
71
- });
72
- }
73
- else if (op === 'N') {
74
- mismatches.push({
75
- start: roffset,
76
- type: 'skip',
77
- base: 'N',
78
- length: len,
79
- });
80
- }
81
- else if (op === 'X') {
82
- const r = (seq === null || seq === void 0 ? void 0 : seq.slice(soffset, soffset + len)) || [];
83
- const q = (qual === null || qual === void 0 ? void 0 : qual.subarray(soffset, soffset + len)) || [];
84
- for (let j = 0; j < len; j++) {
85
- mismatches.push({
86
- start: roffset + j,
87
- type: 'mismatch',
88
- base: r[j],
89
- qual: q[j],
90
- length: 1,
91
- });
92
- }
93
- soffset += len;
94
- }
95
- else if (op === 'H') {
96
- mismatches.push({
97
- start: roffset,
98
- type: 'hardclip',
99
- base: `H${len}`,
100
- cliplen: len,
101
- length: 1,
102
- });
103
- }
104
- else if (op === 'S') {
105
- mismatches.push({
106
- start: roffset,
107
- type: 'softclip',
108
- base: `S${len}`,
109
- cliplen: len,
110
- length: 1,
111
- });
112
- soffset += len;
113
- }
114
- if (op !== 'I' && op !== 'S' && op !== 'H') {
115
- roffset += len;
116
- }
117
- }
118
- return mismatches;
119
- }
120
- /**
121
- * parse a SAM MD tag to find mismatching bases of the template versus the
122
- * reference @returns array of mismatches and their positions
123
- */
124
- function mdToMismatches(mdstring, ops, cigarMismatches, seq, qual) {
125
- let curr = { start: 0, base: '', length: 0, type: 'mismatch' };
126
- let lastCigar = 0;
127
- let lastTemplateOffset = 0;
128
- let lastRefOffset = 0;
129
- let lastSkipPos = 0;
130
- const mismatchRecords = [];
131
- const skips = cigarMismatches.filter(cigar => cigar.type === 'skip');
132
- // convert a position on the reference sequence to a position
133
- // on the template sequence, taking into account hard and soft
134
- // clipping of reads
135
- function nextRecord() {
136
- mismatchRecords.push(curr);
137
- // get a new mismatch record ready
138
- curr = {
139
- start: curr.start + curr.length,
140
- length: 0,
141
- base: '',
142
- type: 'mismatch',
143
- };
144
- }
145
- function getTemplateCoordLocal(refCoord) {
146
- let templateOffset = lastTemplateOffset;
147
- let refOffset = lastRefOffset;
148
- for (let i = lastCigar; i < ops.length && refOffset <= refCoord; i += 2, lastCigar = i) {
149
- const len = +ops[i];
150
- const op = ops[i + 1];
151
- if (op === 'S' || op === 'I') {
152
- templateOffset += len;
153
- }
154
- else if (op === 'D' || op === 'P' || op === 'N') {
155
- refOffset += len;
156
- }
157
- else if (op !== 'H') {
158
- templateOffset += len;
159
- refOffset += len;
160
- }
161
- }
162
- lastTemplateOffset = templateOffset;
163
- lastRefOffset = refOffset;
164
- return templateOffset - (refOffset - refCoord);
165
- }
166
- // now actually parse the MD string
167
- const md = mdstring.match(mdRegex) || [];
168
- for (const token of md) {
169
- const num = +token;
170
- if (!Number.isNaN(num)) {
171
- curr.start += num;
172
- }
173
- else if (token.startsWith('^')) {
174
- curr.start += token.length - 1;
175
- }
176
- else {
177
- // mismatch
178
- // eslint-disable-next-line @typescript-eslint/prefer-for-of
179
- for (let j = 0; j < token.length; j += 1) {
180
- curr.length = 1;
181
- while (lastSkipPos < skips.length) {
182
- const mismatch = skips[lastSkipPos];
183
- if (curr.start >= mismatch.start) {
184
- curr.start += mismatch.length;
185
- lastSkipPos++;
186
- }
187
- else {
188
- break;
189
- }
190
- }
191
- const s = getTemplateCoordLocal(curr.start);
192
- curr.base = seq[s] || 'X';
193
- curr.qual = qual === null || qual === void 0 ? void 0 : qual[s];
194
- curr.altbase = token;
195
- nextRecord();
196
- }
197
- }
198
- }
199
- return mismatchRecords;
200
- }
201
22
  function getMismatches(cigar, md, seq, ref, qual) {
202
23
  let mismatches = [];
203
24
  const ops = parseCigar(cigar);
204
25
  // parse the CIGAR tag if it has one
205
26
  if (cigar) {
206
- mismatches = mismatches.concat(cigarToMismatches(ops, seq, ref, qual));
27
+ mismatches = mismatches.concat((0, cigarToMismatches_1.cigarToMismatches)(ops, seq, ref, qual));
207
28
  }
208
29
  // now let's look for CRAM or MD mismatches
209
30
  if (md && seq) {
210
- mismatches = mismatches.concat(mdToMismatches(md, ops, mismatches, seq, qual));
31
+ mismatches = mismatches.concat((0, mdToMismatches_1.mdToMismatches)(md, ops, mismatches, seq, qual));
211
32
  }
212
33
  return mismatches;
213
34
  }
214
- // get relative reference sequence positions for positions given relative to
215
- // the read sequence
216
- function* getNextRefPos(cigarOps, positions) {
217
- let readPos = 0;
218
- let refPos = 0;
219
- let currPos = 0;
220
- for (let i = 0; i < cigarOps.length && currPos < positions.length; i += 2) {
221
- const len = +cigarOps[i];
222
- const op = cigarOps[i + 1];
223
- if (op === 'S' || op === 'I') {
224
- for (let i = 0; i < len && currPos < positions.length; i++) {
225
- if (positions[currPos] === readPos + i) {
226
- currPos++;
227
- }
228
- }
229
- readPos += len;
230
- }
231
- else if (op === 'D' || op === 'N') {
232
- refPos += len;
233
- }
234
- else if (op === 'M' || op === 'X' || op === '=') {
235
- for (let i = 0; i < len && currPos < positions.length; i++) {
236
- if (positions[currPos] === readPos + i) {
237
- yield refPos + i;
238
- currPos++;
239
- }
240
- }
241
- readPos += len;
242
- refPos += len;
243
- }
244
- }
245
- }
246
- function getModificationProbabilities(feature) {
247
- var _a;
248
- const m = (0, util_2.getTagAlt)(feature, 'ML', 'Ml') || [];
249
- return m
250
- ? (typeof m === 'string' ? m.split(',').map(e => +e) : m).map(e => e / 255)
251
- : (_a = (0, util_2.getTagAlt)(feature, 'MP', 'Mp')) === null || _a === void 0 ? void 0 : _a.split('').map(s => s.charCodeAt(0) - 33).map(elt => Math.min(1, elt / 50));
252
- }
253
- function getMethBins(feature) {
254
- const fstart = feature.get('start');
255
- const fend = feature.get('end');
256
- const fstrand = feature.get('strand');
257
- const flen = fend - fstart;
258
- const mm = (0, util_2.getTagAlt)(feature, 'MM', 'Mm') || '';
259
- const methBins = new Array(flen);
260
- const methProbs = new Array(flen);
261
- const seq = feature.get('seq');
262
- if (seq) {
263
- const ops = parseCigar(feature.get('CIGAR'));
264
- const probabilities = getModificationProbabilities(feature);
265
- const modifications = getModificationPositions(mm, seq, fstrand);
266
- let probIndex = 0;
267
- for (const { type, positions } of modifications) {
268
- if (type === 'm') {
269
- for (const ref of getNextRefPos(ops, positions)) {
270
- const prob = (probabilities === null || probabilities === void 0 ? void 0 : probabilities[probIndex]) || 0;
271
- probIndex++;
272
- if (ref >= 0 && ref < flen) {
273
- methBins[ref] = 1;
274
- methProbs[ref] = prob;
275
- }
276
- }
277
- }
278
- }
279
- }
280
- return { methBins, methProbs };
281
- }
282
- function getModificationPositions(mm, fseq, fstrand) {
283
- const seq = fstrand === -1 ? (0, util_1.revcom)(fseq) : fseq;
284
- const mods = mm.split(';').filter(mod => !!mod);
285
- const result = [];
286
- for (const mod of mods) {
287
- const [basemod, ...skips] = mod.split(',');
288
- // regexes based on parse_mm.pl from hts-specs
289
- const matches = modificationRegex.exec(basemod);
290
- if (!matches) {
291
- throw new Error('bad format for MM tag');
292
- }
293
- const [, base, strand, typestr] = matches;
294
- // can be a multi e.g. C+mh for both meth (m) and hydroxymeth (h) so
295
- // split, and they can also be chemical codes (ChEBI) e.g. C+16061
296
- const types = typestr.split(/(\d+|.)/).filter(f => !!f);
297
- if (strand === '-') {
298
- console.warn('unsupported negative strand modifications');
299
- // make sure to return a somewhat matching type even in this case
300
- result.push({ type: 'unsupported', positions: [] });
301
- }
302
- // this logic also based on parse_mm.pl from hts-specs is that in the
303
- // sequence of the read, if we have a modification type e.g. C+m;2 and a
304
- // sequence ACGTACGTAC we skip the two instances of C and go to the last
305
- // C
306
- for (const type of types) {
307
- let i = 0;
308
- const positions = [];
309
- for (const d of skips) {
310
- let delta = +d;
311
- do {
312
- if (base === 'N' || base === seq[i]) {
313
- delta--;
314
- }
315
- i++;
316
- } while (delta >= 0 && i < seq.length);
317
- const temp = i - 1;
318
- positions.push(fstrand === -1 ? seq.length - 1 - temp : temp);
319
- }
320
- if (fstrand === -1) {
321
- positions.sort((a, b) => a - b);
322
- }
323
- result.push({
324
- type,
325
- positions,
326
- });
327
- }
328
- }
329
- return result;
330
- }
331
- function getModificationTypes(mm) {
332
- return mm
333
- .split(';')
334
- .filter(mod => !!mod)
335
- .flatMap(mod => {
336
- const basemod = mod.split(',')[0];
337
- const matches = modificationRegex.exec(basemod);
338
- if (!matches) {
339
- throw new Error(`bad format for MM tag: ${mm}`);
340
- }
341
- const typestr = matches[3];
342
- // can be a multi e.g. C+mh for both meth (m) and hydroxymeth (h) so
343
- // split, and they can also be chemical codes (ChEBI) e.g. C+16061
344
- return typestr.split(/(\d+|.)/).filter(f => !!f);
345
- });
346
- }
347
35
  function getOrientedCigar(flip, cigar) {
348
36
  if (flip) {
349
37
  const ret = [];
@@ -364,7 +52,7 @@ function getOrientedCigar(flip, cigar) {
364
52
  }
365
53
  function getOrientedMismatches(flip, cigar) {
366
54
  const p = parseCigar(cigar);
367
- return cigarToMismatches(flip ? getOrientedCigar(flip, p) : p);
55
+ return (0, cigarToMismatches_1.cigarToMismatches)(flip ? getOrientedCigar(flip, p) : p);
368
56
  }
369
57
  function getLengthOnRef(cigar) {
370
58
  const cigarOps = parseCigar(cigar);
@@ -407,9 +95,8 @@ function getClip(cigar, strand) {
407
95
  ? +(startClip.exec(cigar) || [])[1] || 0
408
96
  : +(endClip.exec(cigar) || [])[1] || 0;
409
97
  }
410
- function getTag(f, tag) {
411
- const tags = f.get('tags');
412
- return tags ? tags[tag] : f.get(tag);
98
+ function getTag(feature, tag) {
99
+ return feature.get('tags')[tag];
413
100
  }
414
101
  // produces a list of "feature-like" object from parsing supplementary
415
102
  // alignments in the SA tag
@@ -447,3 +134,5 @@ function featurizeSA(SA, id, strand, readName, normalize) {
447
134
  };
448
135
  })) || []);
449
136
  }
137
+ var getNextRefPos_1 = require("./getNextRefPos");
138
+ Object.defineProperty(exports, "getNextRefPos", { enumerable: true, get: function () { return getNextRefPos_1.getNextRefPos; } });
@@ -0,0 +1,3 @@
1
+ import { Mismatch } from '../shared/types';
2
+ import { Buffer } from 'buffer';
3
+ export declare function mdToMismatches(mdstring: string, ops: string[], cigarMismatches: Mismatch[], seq: string, qual?: Buffer | number[] | null): Mismatch[];
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.mdToMismatches = mdToMismatches;
4
+ const mdRegex = new RegExp(/(\d+|\^[a-z]+|[a-z])/gi);
5
+ function mdToMismatches(mdstring, ops, cigarMismatches, seq, qual) {
6
+ let curr = { start: 0, base: '', length: 0, type: 'mismatch' };
7
+ let lastCigar = 0;
8
+ let lastTemplateOffset = 0;
9
+ let lastRefOffset = 0;
10
+ let lastSkipPos = 0;
11
+ const mismatchRecords = [];
12
+ const skips = cigarMismatches.filter(cigar => cigar.type === 'skip');
13
+ // convert a position on the reference sequence to a position on the template
14
+ // sequence, taking into account hard and soft clipping of reads
15
+ function nextRecord() {
16
+ mismatchRecords.push(curr);
17
+ // get a new mismatch record ready
18
+ curr = {
19
+ start: curr.start + curr.length,
20
+ length: 0,
21
+ base: '',
22
+ type: 'mismatch',
23
+ };
24
+ }
25
+ function getTemplateCoordLocal(refCoord) {
26
+ let templateOffset = lastTemplateOffset;
27
+ let refOffset = lastRefOffset;
28
+ for (let i = lastCigar; i < ops.length && refOffset <= refCoord; i += 2, lastCigar = i) {
29
+ const len = +ops[i];
30
+ const op = ops[i + 1];
31
+ if (op === 'S' || op === 'I') {
32
+ templateOffset += len;
33
+ }
34
+ else if (op === 'D' || op === 'P' || op === 'N') {
35
+ refOffset += len;
36
+ }
37
+ else if (op !== 'H') {
38
+ templateOffset += len;
39
+ refOffset += len;
40
+ }
41
+ }
42
+ lastTemplateOffset = templateOffset;
43
+ lastRefOffset = refOffset;
44
+ return templateOffset - (refOffset - refCoord);
45
+ }
46
+ // now actually parse the MD string
47
+ const md = mdstring.match(mdRegex) || [];
48
+ for (const token of md) {
49
+ const num = +token;
50
+ if (!Number.isNaN(num)) {
51
+ curr.start += num;
52
+ }
53
+ else if (token.startsWith('^')) {
54
+ curr.start += token.length - 1;
55
+ }
56
+ else {
57
+ // mismatch
58
+ // eslint-disable-next-line @typescript-eslint/prefer-for-of
59
+ for (let j = 0; j < token.length; j += 1) {
60
+ curr.length = 1;
61
+ while (lastSkipPos < skips.length) {
62
+ const mismatch = skips[lastSkipPos];
63
+ if (curr.start >= mismatch.start) {
64
+ curr.start += mismatch.length;
65
+ lastSkipPos++;
66
+ }
67
+ else {
68
+ break;
69
+ }
70
+ }
71
+ const s = getTemplateCoordLocal(curr.start);
72
+ curr.base = seq[s] || 'X';
73
+ curr.qual = qual === null || qual === void 0 ? void 0 : qual[s];
74
+ curr.altbase = token;
75
+ nextRecord();
76
+ }
77
+ }
78
+ }
79
+ return mismatchRecords;
80
+ }
@@ -0,0 +1,19 @@
1
+ import { Feature } from '@jbrowse/core/util';
2
+ export declare function getModProbabilities(feature: Feature): number[] | undefined;
3
+ export declare function getModPositions(mm: string, fseq: string, fstrand: number): {
4
+ type: string;
5
+ positions: number[];
6
+ base: string;
7
+ strand: string;
8
+ }[];
9
+ export declare function getModTypes(mm: string): {
10
+ type: string;
11
+ base: string;
12
+ strand: string;
13
+ }[];
14
+ export declare function getMethBins(feature: Feature, cigarOps: string[]): {
15
+ methBins: number[];
16
+ hydroxyMethBins: number[];
17
+ methProbs: number[];
18
+ hydroxyMethProbs: number[];
19
+ };
@@ -0,0 +1,144 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getModProbabilities = getModProbabilities;
4
+ exports.getModPositions = getModPositions;
5
+ exports.getModTypes = getModTypes;
6
+ exports.getMethBins = getMethBins;
7
+ const util_1 = require("@jbrowse/core/util");
8
+ const util_2 = require("../util");
9
+ const MismatchParser_1 = require("../MismatchParser");
10
+ const modificationRegex = new RegExp(/([A-Z])([-+])([^,.?]+)([.?])?/);
11
+ // ML stores probabilities as array of numerics and MP is scaled phred scores
12
+ // https://github.com/samtools/hts-specs/pull/418/files#diff-e765c6479316309f56b636f88189cdde8c40b854c7bdcce9ee7fe87a4e76febcR596
13
+ //
14
+ // if we have ML or Ml, it is an 8bit probability, divide by 255
15
+ //
16
+ // if we have MP or Mp it is phred scaled ASCII, which can go up to 90 but has
17
+ // very high likelihood basecalls at that point, we really only care about low
18
+ // qual calls <20 approx
19
+ function getModProbabilities(feature) {
20
+ var _a;
21
+ const m = (0, util_2.getTagAlt)(feature, 'ML', 'Ml') || [];
22
+ return m
23
+ ? (typeof m === 'string' ? m.split(',').map(e => +e) : m).map(e => e / 255)
24
+ : (_a = (0, util_2.getTagAlt)(feature, 'MP', 'Mp')) === null || _a === void 0 ? void 0 : _a.split('').map(s => s.charCodeAt(0) - 33).map(elt => Math.min(1, elt / 50));
25
+ }
26
+ function getModPositions(mm, fseq, fstrand) {
27
+ const seq = fstrand === -1 ? (0, util_1.revcom)(fseq) : fseq;
28
+ const mods = mm.split(';').filter(mod => !!mod);
29
+ const result = [];
30
+ for (const mod of mods) {
31
+ const [basemod, ...skips] = mod.split(',');
32
+ // regexes based on parse_mm.pl from hts-specs
33
+ // https://github.com/samtools/hts-specs/blob/master/test/SAMtags/parse_mm.pl
34
+ const matches = modificationRegex.exec(basemod);
35
+ if (!matches) {
36
+ throw new Error('bad format for MM tag');
37
+ }
38
+ const [, base, strand, typestr] = matches;
39
+ // can be a multi e.g. C+mh for both meth (m) and hydroxymeth (h) so split,
40
+ // and they can also be chemical codes (ChEBI) e.g. C+16061
41
+ const types = typestr.split(/(\d+|.)/).filter(f => !!f);
42
+ if (strand === '-') {
43
+ console.warn('unsupported negative strand modifications');
44
+ result.push({
45
+ type: 'unsupported',
46
+ positions: [],
47
+ base: base,
48
+ strand: strand,
49
+ });
50
+ }
51
+ // this logic based on parse_mm.pl from hts-specs
52
+ for (const type of types) {
53
+ let i = 0;
54
+ const positions = [];
55
+ for (const d of skips) {
56
+ let delta = +d;
57
+ do {
58
+ if (base === 'N' || base === seq[i]) {
59
+ delta--;
60
+ }
61
+ i++;
62
+ } while (delta >= 0 && i < seq.length);
63
+ if (fstrand === -1) {
64
+ const pos = seq.length - i;
65
+ if (pos >= 0) {
66
+ // avoid negative-number-positions in array, seen in #4629 cause
67
+ // unknown, could warrant some further investigation
68
+ positions.unshift(pos);
69
+ }
70
+ }
71
+ else {
72
+ positions.push(i - 1);
73
+ }
74
+ }
75
+ result.push({
76
+ type,
77
+ base: base,
78
+ strand: strand,
79
+ positions,
80
+ });
81
+ }
82
+ }
83
+ return result;
84
+ }
85
+ function getModTypes(mm) {
86
+ return mm
87
+ .split(';')
88
+ .filter(mod => !!mod)
89
+ .flatMap(mod => {
90
+ const basemod = mod.split(',')[0];
91
+ const matches = modificationRegex.exec(basemod);
92
+ if (!matches) {
93
+ throw new Error('bad format for MM tag');
94
+ }
95
+ const [, base, strand, typestr] = matches;
96
+ // can be a multi e.g. C+mh for both meth (m) and hydroxymeth (h) so
97
+ // split, and they can also be chemical codes (ChEBI) e.g. C+16061
98
+ return typestr
99
+ .split(/(\d+|.)/)
100
+ .filter(f => !!f)
101
+ .map(type => ({
102
+ type,
103
+ base: base,
104
+ strand: strand,
105
+ }));
106
+ });
107
+ }
108
+ function getMethBins(feature, cigarOps) {
109
+ const fstart = feature.get('start');
110
+ const fend = feature.get('end');
111
+ const fstrand = feature.get('strand');
112
+ const flen = fend - fstart;
113
+ const mm = (0, util_2.getTagAlt)(feature, 'MM', 'Mm') || '';
114
+ const methBins = [];
115
+ const hydroxyMethBins = [];
116
+ const methProbs = [];
117
+ const hydroxyMethProbs = [];
118
+ const seq = feature.get('seq');
119
+ if (seq) {
120
+ const probabilities = getModProbabilities(feature);
121
+ const modifications = getModPositions(mm, seq, fstrand);
122
+ let probIndex = 0;
123
+ for (const { type, positions } of modifications) {
124
+ for (const { ref, idx } of (0, MismatchParser_1.getNextRefPos)(cigarOps, positions)) {
125
+ const idx2 = probIndex + (fstrand === -1 ? positions.length - 1 - idx : idx);
126
+ const prob = (probabilities === null || probabilities === void 0 ? void 0 : probabilities[idx2]) || 0;
127
+ if (type === 'm') {
128
+ if (ref >= 0 && ref < flen) {
129
+ methBins[ref] = 1;
130
+ methProbs[ref] = prob;
131
+ }
132
+ }
133
+ else if (type === 'h') {
134
+ if (ref >= 0 && ref < flen) {
135
+ hydroxyMethBins[ref] = 1;
136
+ hydroxyMethProbs[ref] = prob;
137
+ }
138
+ }
139
+ }
140
+ probIndex += positions.length;
141
+ }
142
+ }
143
+ return { methBins, hydroxyMethBins, methProbs, hydroxyMethProbs };
144
+ }