@jbrowse/plugin-comparative-adapters 2.6.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 (178) hide show
  1. package/LICENSE +201 -0
  2. package/dist/ChainAdapter/ChainAdapter.d.ts +19 -0
  3. package/dist/ChainAdapter/ChainAdapter.js +22 -0
  4. package/dist/ChainAdapter/ChainAdapter.js.map +1 -0
  5. package/dist/ChainAdapter/configSchema.d.ts +39 -0
  6. package/dist/ChainAdapter/configSchema.js +45 -0
  7. package/dist/ChainAdapter/configSchema.js.map +1 -0
  8. package/dist/ChainAdapter/index.d.ts +3 -0
  9. package/dist/ChainAdapter/index.js +42 -0
  10. package/dist/ChainAdapter/index.js.map +1 -0
  11. package/dist/ChainAdapter/util.d.ts +16 -0
  12. package/dist/ChainAdapter/util.js +134 -0
  13. package/dist/ChainAdapter/util.js.map +1 -0
  14. package/dist/DeltaAdapter/DeltaAdapter.d.ts +20 -0
  15. package/dist/DeltaAdapter/DeltaAdapter.js +22 -0
  16. package/dist/DeltaAdapter/DeltaAdapter.js.map +1 -0
  17. package/dist/DeltaAdapter/configSchema.d.ts +39 -0
  18. package/dist/DeltaAdapter/configSchema.js +45 -0
  19. package/dist/DeltaAdapter/configSchema.js.map +1 -0
  20. package/dist/DeltaAdapter/index.d.ts +3 -0
  21. package/dist/DeltaAdapter/index.js +42 -0
  22. package/dist/DeltaAdapter/index.js.map +1 -0
  23. package/dist/DeltaAdapter/util.d.ts +17 -0
  24. package/dist/DeltaAdapter/util.js +152 -0
  25. package/dist/DeltaAdapter/util.js.map +1 -0
  26. package/dist/MCScanAnchorsAdapter/MCScanAnchorsAdapter.d.ts +33 -0
  27. package/dist/MCScanAnchorsAdapter/MCScanAnchorsAdapter.js +96 -0
  28. package/dist/MCScanAnchorsAdapter/MCScanAnchorsAdapter.js.map +1 -0
  29. package/dist/MCScanAnchorsAdapter/configSchema.d.ts +40 -0
  30. package/dist/MCScanAnchorsAdapter/configSchema.js +48 -0
  31. package/dist/MCScanAnchorsAdapter/configSchema.js.map +1 -0
  32. package/dist/MCScanAnchorsAdapter/index.d.ts +3 -0
  33. package/dist/MCScanAnchorsAdapter/index.js +42 -0
  34. package/dist/MCScanAnchorsAdapter/index.js.map +1 -0
  35. package/dist/MCScanSimpleAnchorsAdapter/MCScanSimpleAnchorsAdapter.d.ts +41 -0
  36. package/dist/MCScanSimpleAnchorsAdapter/MCScanSimpleAnchorsAdapter.js +121 -0
  37. package/dist/MCScanSimpleAnchorsAdapter/MCScanSimpleAnchorsAdapter.js.map +1 -0
  38. package/dist/MCScanSimpleAnchorsAdapter/configSchema.d.ts +40 -0
  39. package/dist/MCScanSimpleAnchorsAdapter/configSchema.js +48 -0
  40. package/dist/MCScanSimpleAnchorsAdapter/configSchema.js.map +1 -0
  41. package/dist/MCScanSimpleAnchorsAdapter/index.d.ts +3 -0
  42. package/dist/MCScanSimpleAnchorsAdapter/index.js +42 -0
  43. package/dist/MCScanSimpleAnchorsAdapter/index.js.map +1 -0
  44. package/dist/MashMapAdapter/MashMapAdapter.d.ts +5 -0
  45. package/dist/MashMapAdapter/MashMapAdapter.js +42 -0
  46. package/dist/MashMapAdapter/MashMapAdapter.js.map +1 -0
  47. package/dist/MashMapAdapter/configSchema.d.ts +37 -0
  48. package/dist/MashMapAdapter/configSchema.js +45 -0
  49. package/dist/MashMapAdapter/configSchema.js.map +1 -0
  50. package/dist/MashMapAdapter/index.d.ts +3 -0
  51. package/dist/MashMapAdapter/index.js +42 -0
  52. package/dist/MashMapAdapter/index.js.map +1 -0
  53. package/dist/PAFAdapter/PAFAdapter.d.ts +20 -0
  54. package/dist/PAFAdapter/PAFAdapter.js +152 -0
  55. package/dist/PAFAdapter/PAFAdapter.js.map +1 -0
  56. package/dist/PAFAdapter/SyntenyFeature.d.ts +4 -0
  57. package/dist/PAFAdapter/SyntenyFeature.js +17 -0
  58. package/dist/PAFAdapter/SyntenyFeature.js.map +1 -0
  59. package/dist/PAFAdapter/configSchema.d.ts +37 -0
  60. package/dist/PAFAdapter/configSchema.js +45 -0
  61. package/dist/PAFAdapter/configSchema.js.map +1 -0
  62. package/dist/PAFAdapter/index.d.ts +3 -0
  63. package/dist/PAFAdapter/index.js +42 -0
  64. package/dist/PAFAdapter/index.js.map +1 -0
  65. package/dist/PAFAdapter/util.d.ts +20 -0
  66. package/dist/PAFAdapter/util.js +134 -0
  67. package/dist/PAFAdapter/util.js.map +1 -0
  68. package/dist/index.d.ts +6 -0
  69. package/dist/index.js +51 -0
  70. package/dist/index.js.map +1 -0
  71. package/dist/util.d.ts +16 -0
  72. package/dist/util.js +57 -0
  73. package/dist/util.js.map +1 -0
  74. package/esm/ChainAdapter/ChainAdapter.d.ts +19 -0
  75. package/esm/ChainAdapter/ChainAdapter.js +16 -0
  76. package/esm/ChainAdapter/ChainAdapter.js.map +1 -0
  77. package/esm/ChainAdapter/configSchema.d.ts +39 -0
  78. package/esm/ChainAdapter/configSchema.js +43 -0
  79. package/esm/ChainAdapter/configSchema.js.map +1 -0
  80. package/esm/ChainAdapter/index.d.ts +3 -0
  81. package/esm/ChainAdapter/index.js +14 -0
  82. package/esm/ChainAdapter/index.js.map +1 -0
  83. package/esm/ChainAdapter/util.d.ts +16 -0
  84. package/esm/ChainAdapter/util.js +130 -0
  85. package/esm/ChainAdapter/util.js.map +1 -0
  86. package/esm/DeltaAdapter/DeltaAdapter.d.ts +20 -0
  87. package/esm/DeltaAdapter/DeltaAdapter.js +16 -0
  88. package/esm/DeltaAdapter/DeltaAdapter.js.map +1 -0
  89. package/esm/DeltaAdapter/configSchema.d.ts +39 -0
  90. package/esm/DeltaAdapter/configSchema.js +43 -0
  91. package/esm/DeltaAdapter/configSchema.js.map +1 -0
  92. package/esm/DeltaAdapter/index.d.ts +3 -0
  93. package/esm/DeltaAdapter/index.js +14 -0
  94. package/esm/DeltaAdapter/index.js.map +1 -0
  95. package/esm/DeltaAdapter/util.d.ts +17 -0
  96. package/esm/DeltaAdapter/util.js +148 -0
  97. package/esm/DeltaAdapter/util.js.map +1 -0
  98. package/esm/MCScanAnchorsAdapter/MCScanAnchorsAdapter.d.ts +33 -0
  99. package/esm/MCScanAnchorsAdapter/MCScanAnchorsAdapter.js +94 -0
  100. package/esm/MCScanAnchorsAdapter/MCScanAnchorsAdapter.js.map +1 -0
  101. package/esm/MCScanAnchorsAdapter/configSchema.d.ts +40 -0
  102. package/esm/MCScanAnchorsAdapter/configSchema.js +46 -0
  103. package/esm/MCScanAnchorsAdapter/configSchema.js.map +1 -0
  104. package/esm/MCScanAnchorsAdapter/index.d.ts +3 -0
  105. package/esm/MCScanAnchorsAdapter/index.js +14 -0
  106. package/esm/MCScanAnchorsAdapter/index.js.map +1 -0
  107. package/esm/MCScanSimpleAnchorsAdapter/MCScanSimpleAnchorsAdapter.d.ts +41 -0
  108. package/esm/MCScanSimpleAnchorsAdapter/MCScanSimpleAnchorsAdapter.js +116 -0
  109. package/esm/MCScanSimpleAnchorsAdapter/MCScanSimpleAnchorsAdapter.js.map +1 -0
  110. package/esm/MCScanSimpleAnchorsAdapter/configSchema.d.ts +40 -0
  111. package/esm/MCScanSimpleAnchorsAdapter/configSchema.js +46 -0
  112. package/esm/MCScanSimpleAnchorsAdapter/configSchema.js.map +1 -0
  113. package/esm/MCScanSimpleAnchorsAdapter/index.d.ts +3 -0
  114. package/esm/MCScanSimpleAnchorsAdapter/index.js +14 -0
  115. package/esm/MCScanSimpleAnchorsAdapter/index.js.map +1 -0
  116. package/esm/MashMapAdapter/MashMapAdapter.d.ts +5 -0
  117. package/esm/MashMapAdapter/MashMapAdapter.js +36 -0
  118. package/esm/MashMapAdapter/MashMapAdapter.js.map +1 -0
  119. package/esm/MashMapAdapter/configSchema.d.ts +37 -0
  120. package/esm/MashMapAdapter/configSchema.js +43 -0
  121. package/esm/MashMapAdapter/configSchema.js.map +1 -0
  122. package/esm/MashMapAdapter/index.d.ts +3 -0
  123. package/esm/MashMapAdapter/index.js +14 -0
  124. package/esm/MashMapAdapter/index.js.map +1 -0
  125. package/esm/PAFAdapter/PAFAdapter.d.ts +20 -0
  126. package/esm/PAFAdapter/PAFAdapter.js +147 -0
  127. package/esm/PAFAdapter/PAFAdapter.js.map +1 -0
  128. package/esm/PAFAdapter/SyntenyFeature.d.ts +4 -0
  129. package/esm/PAFAdapter/SyntenyFeature.js +14 -0
  130. package/esm/PAFAdapter/SyntenyFeature.js.map +1 -0
  131. package/esm/PAFAdapter/configSchema.d.ts +37 -0
  132. package/esm/PAFAdapter/configSchema.js +43 -0
  133. package/esm/PAFAdapter/configSchema.js.map +1 -0
  134. package/esm/PAFAdapter/index.d.ts +3 -0
  135. package/esm/PAFAdapter/index.js +14 -0
  136. package/esm/PAFAdapter/index.js.map +1 -0
  137. package/esm/PAFAdapter/util.d.ts +20 -0
  138. package/esm/PAFAdapter/util.js +127 -0
  139. package/esm/PAFAdapter/util.js.map +1 -0
  140. package/esm/index.d.ts +6 -0
  141. package/esm/index.js +45 -0
  142. package/esm/index.js.map +1 -0
  143. package/esm/util.d.ts +16 -0
  144. package/esm/util.js +49 -0
  145. package/esm/util.js.map +1 -0
  146. package/package.json +63 -0
  147. package/src/ChainAdapter/ChainAdapter.ts +18 -0
  148. package/src/ChainAdapter/configSchema.ts +50 -0
  149. package/src/ChainAdapter/index.ts +18 -0
  150. package/src/ChainAdapter/util.ts +170 -0
  151. package/src/DeltaAdapter/DeltaAdapter.ts +18 -0
  152. package/src/DeltaAdapter/configSchema.ts +50 -0
  153. package/src/DeltaAdapter/index.ts +18 -0
  154. package/src/DeltaAdapter/util.ts +149 -0
  155. package/src/MCScanAnchorsAdapter/MCScanAnchorsAdapter.test.ts +45 -0
  156. package/src/MCScanAnchorsAdapter/MCScanAnchorsAdapter.ts +134 -0
  157. package/src/MCScanAnchorsAdapter/configSchema.ts +52 -0
  158. package/src/MCScanAnchorsAdapter/index.ts +20 -0
  159. package/src/MCScanAnchorsAdapter/test_data/grape.bed.gz +0 -0
  160. package/src/MCScanAnchorsAdapter/test_data/grape.peach.anchors.gz +0 -0
  161. package/src/MCScanAnchorsAdapter/test_data/peach.bed.gz +0 -0
  162. package/src/MCScanSimpleAnchorsAdapter/MCScanSimpleAnchorsAdapter.ts +157 -0
  163. package/src/MCScanSimpleAnchorsAdapter/configSchema.ts +52 -0
  164. package/src/MCScanSimpleAnchorsAdapter/index.ts +19 -0
  165. package/src/MashMapAdapter/MashMapAdapter.ts +40 -0
  166. package/src/MashMapAdapter/configSchema.ts +51 -0
  167. package/src/MashMapAdapter/index.ts +18 -0
  168. package/src/PAFAdapter/PAFAdapter.test.ts +37 -0
  169. package/src/PAFAdapter/PAFAdapter.ts +181 -0
  170. package/src/PAFAdapter/SyntenyFeature.ts +15 -0
  171. package/src/PAFAdapter/configSchema.ts +50 -0
  172. package/src/PAFAdapter/index.ts +18 -0
  173. package/src/PAFAdapter/test_data/grape.peach.anchors +14966 -0
  174. package/src/PAFAdapter/test_data/peach_grape.paf +30 -0
  175. package/src/PAFAdapter/util.test.ts +7 -0
  176. package/src/PAFAdapter/util.ts +176 -0
  177. package/src/index.ts +62 -0
  178. package/src/util.ts +66 -0
@@ -0,0 +1,52 @@
1
+ import { ConfigurationSchema } from '@jbrowse/core/configuration'
2
+
3
+ /**
4
+ * #config MCScanAnchorsAdapter
5
+ */
6
+ function x() {} // eslint-disable-line @typescript-eslint/no-unused-vars
7
+
8
+ const MCScanAnchorsAdapter = ConfigurationSchema(
9
+ 'MCScanAnchorsAdapter',
10
+ {
11
+ /**
12
+ * #slot
13
+ */
14
+ mcscanAnchorsLocation: {
15
+ type: 'fileLocation',
16
+ defaultValue: {
17
+ uri: '/path/to/mcscan.anchors',
18
+ locationType: 'UriLocation',
19
+ },
20
+ },
21
+ /**
22
+ * #slot
23
+ */
24
+ bed1Location: {
25
+ type: 'fileLocation',
26
+ defaultValue: {
27
+ uri: '/path/to/file.bed',
28
+ locationType: 'UriLocation',
29
+ },
30
+ },
31
+ /**
32
+ * #slot
33
+ */
34
+ bed2Location: {
35
+ type: 'fileLocation',
36
+ defaultValue: {
37
+ uri: '/path/to/file.bed',
38
+ locationType: 'UriLocation',
39
+ },
40
+ },
41
+ /**
42
+ * #slot
43
+ */
44
+ assemblyNames: {
45
+ type: 'stringArray',
46
+ defaultValue: [],
47
+ },
48
+ },
49
+ { explicitlyTyped: true },
50
+ )
51
+
52
+ export default MCScanAnchorsAdapter
@@ -0,0 +1,20 @@
1
+ import PluginManager from '@jbrowse/core/PluginManager'
2
+ import AdapterType from '@jbrowse/core/pluggableElementTypes/AdapterType'
3
+ import configSchema from './configSchema'
4
+
5
+ export default (pluginManager: PluginManager) => {
6
+ pluginManager.addAdapterType(
7
+ () =>
8
+ new AdapterType({
9
+ name: 'MCScanAnchorsAdapter',
10
+ displayName: 'MCScan anchors adapter',
11
+ configSchema,
12
+ adapterMetadata: {
13
+ hiddenFromGUI: true,
14
+ },
15
+
16
+ getAdapterClass: () =>
17
+ import('./MCScanAnchorsAdapter').then(r => r.default),
18
+ }),
19
+ )
20
+ }
@@ -0,0 +1,157 @@
1
+ import {
2
+ BaseFeatureDataAdapter,
3
+ BaseOptions,
4
+ } from '@jbrowse/core/data_adapters/BaseAdapter'
5
+ import { Region } from '@jbrowse/core/util/types'
6
+ import { openLocation } from '@jbrowse/core/util/io'
7
+ import { doesIntersect2 } from '@jbrowse/core/util'
8
+ import { ObservableCreate } from '@jbrowse/core/util/rxjs'
9
+ import SimpleFeature, { Feature } from '@jbrowse/core/util/simpleFeature'
10
+ import { readFile, parseBed } from '../util'
11
+
12
+ interface BareFeature {
13
+ refName: string
14
+ start: number
15
+ end: number
16
+ score: number
17
+ name: string
18
+ }
19
+
20
+ type Row = [
21
+ BareFeature,
22
+ BareFeature,
23
+ BareFeature,
24
+ BareFeature,
25
+ number,
26
+ number,
27
+ number,
28
+ ]
29
+
30
+ export default class MCScanAnchorsAdapter extends BaseFeatureDataAdapter {
31
+ private setupP?: Promise<{
32
+ assemblyNames: string[]
33
+ feats: Row[]
34
+ }>
35
+
36
+ public static capabilities = ['getFeatures', 'getRefNames']
37
+
38
+ async setup(opts: BaseOptions) {
39
+ if (!this.setupP) {
40
+ this.setupP = this.setupPre(opts).catch(e => {
41
+ this.setupP = undefined
42
+ throw e
43
+ })
44
+ }
45
+ return this.setupP
46
+ }
47
+ async setupPre(opts: BaseOptions) {
48
+ const assemblyNames = this.getConf('assemblyNames') as string[]
49
+ const pm = this.pluginManager
50
+ const bed1 = openLocation(this.getConf('bed1Location'), pm)
51
+ const bed2 = openLocation(this.getConf('bed2Location'), pm)
52
+ const mcscan = openLocation(this.getConf('mcscanSimpleAnchorsLocation'), pm)
53
+ const [bed1text, bed2text, mcscantext] = await Promise.all(
54
+ [bed1, bed2, mcscan].map(r => readFile(r, opts)),
55
+ )
56
+ const bed1Map = parseBed(bed1text)
57
+ const bed2Map = parseBed(bed2text)
58
+ const feats = mcscantext
59
+ .split(/\n|\r\n|\r/)
60
+ .filter(f => !!f && f !== '###')
61
+ .map((line, index) => {
62
+ const [n11, n12, n21, n22, score, strand] = line.split('\t')
63
+ const r11 = bed1Map.get(n11)
64
+ const r12 = bed1Map.get(n12)
65
+ const r21 = bed2Map.get(n21)
66
+ const r22 = bed2Map.get(n22)
67
+ if (!r11 || !r12 || !r21 || !r22) {
68
+ throw new Error(
69
+ `feature not found, ${n11} ${n12} ${n21} ${n22} ${r11} ${r12} ${r21} ${r22}`,
70
+ )
71
+ }
72
+ return [
73
+ r11,
74
+ r12,
75
+ r21,
76
+ r22,
77
+ +score,
78
+ strand === '-' ? -1 : 1,
79
+ index,
80
+ ] as Row
81
+ })
82
+
83
+ return {
84
+ assemblyNames,
85
+ feats,
86
+ }
87
+ }
88
+
89
+ async hasDataForRefName() {
90
+ // determining this properly is basically a call to getFeatures
91
+ // so is not really that important, and has to be true or else
92
+ // getFeatures is never called (BaseFeatureDataAdapter filters it out)
93
+ return true
94
+ }
95
+
96
+ async getRefNames() {
97
+ // we cannot determine this accurately
98
+ return []
99
+ }
100
+
101
+ getFeatures(region: Region, opts: BaseOptions = {}) {
102
+ return ObservableCreate<Feature>(async observer => {
103
+ const { assemblyNames, feats } = await this.setup(opts)
104
+
105
+ // The index of the assembly name in the region list corresponds to
106
+ // the adapter in the subadapters list
107
+ const index = assemblyNames.indexOf(region.assemblyName)
108
+ if (index !== -1) {
109
+ const flip = index === 0
110
+ feats.forEach(f => {
111
+ const [f11, f12, f21, f22, score, strand, rowNum] = f
112
+ let r1 = {
113
+ refName: f11.refName,
114
+ start: Math.min(f11.start, f12.start),
115
+ end: Math.max(f11.end, f12.end),
116
+ }
117
+ let r2 = {
118
+ refName: f21.refName,
119
+ start: Math.min(f21.start, f22.start),
120
+ end: Math.max(f21.end, f22.end),
121
+ }
122
+ if (!flip) {
123
+ ;[r2, r1] = [r1, r2]
124
+ }
125
+ if (
126
+ r1.refName === region.refName &&
127
+ doesIntersect2(r1.start, r1.end, region.start, region.end)
128
+ ) {
129
+ observer.next(
130
+ new SimpleFeature({
131
+ ...r1,
132
+ uniqueId: `${rowNum}`,
133
+ syntenyId: rowNum,
134
+ assemblyName: assemblyNames[+!flip],
135
+ score,
136
+ strand,
137
+ mate: {
138
+ ...r2,
139
+ assemblyName: assemblyNames[+flip],
140
+ },
141
+ }),
142
+ )
143
+ }
144
+ })
145
+ }
146
+
147
+ observer.complete()
148
+ })
149
+ }
150
+
151
+ /**
152
+ * called to provide a hint that data tied to a certain region
153
+ * will not be needed for the foreseeable future and can be purged
154
+ * from caches, etc
155
+ */
156
+ freeResources(/* { region } */): void {}
157
+ }
@@ -0,0 +1,52 @@
1
+ import { ConfigurationSchema } from '@jbrowse/core/configuration'
2
+
3
+ /**
4
+ * #config MCScanSimpleAnchorsAdapter
5
+ */
6
+ function x() {} // eslint-disable-line @typescript-eslint/no-unused-vars
7
+
8
+ const MCScanSimpleAnchorsAdapter = ConfigurationSchema(
9
+ 'MCScanSimpleAnchorsAdapter',
10
+ {
11
+ /**
12
+ * #slot
13
+ */
14
+ mcscanSimpleAnchorsLocation: {
15
+ type: 'fileLocation',
16
+ defaultValue: {
17
+ uri: '/path/to/mcscan.anchors.simple',
18
+ locationType: 'UriLocation',
19
+ },
20
+ },
21
+ /**
22
+ * #slot
23
+ */
24
+ bed1Location: {
25
+ type: 'fileLocation',
26
+ defaultValue: {
27
+ uri: '/path/to/file.bed',
28
+ locationType: 'UriLocation',
29
+ },
30
+ },
31
+ /**
32
+ * #slot
33
+ */
34
+ bed2Location: {
35
+ type: 'fileLocation',
36
+ defaultValue: {
37
+ uri: '/path/to/file.bed',
38
+ locationType: 'UriLocation',
39
+ },
40
+ },
41
+
42
+ /**
43
+ * #slot
44
+ */
45
+ assemblyNames: {
46
+ type: 'stringArray',
47
+ defaultValue: [],
48
+ },
49
+ },
50
+ { explicitlyTyped: true },
51
+ )
52
+ export default MCScanSimpleAnchorsAdapter
@@ -0,0 +1,19 @@
1
+ import PluginManager from '@jbrowse/core/PluginManager'
2
+ import AdapterType from '@jbrowse/core/pluggableElementTypes/AdapterType'
3
+ import configSchema from './configSchema'
4
+
5
+ export default (pluginManager: PluginManager) => {
6
+ pluginManager.addAdapterType(
7
+ () =>
8
+ new AdapterType({
9
+ name: 'MCScanSimpleAnchorsAdapter',
10
+ displayName: 'MCScan anchors.simple adapter',
11
+ configSchema,
12
+ adapterMetadata: {
13
+ hiddenFromGUI: true,
14
+ },
15
+ getAdapterClass: () =>
16
+ import('./MCScanSimpleAnchorsAdapter').then(r => r.default),
17
+ }),
18
+ )
19
+ }
@@ -0,0 +1,40 @@
1
+ import { BaseOptions } from '@jbrowse/core/data_adapters/BaseAdapter'
2
+ import { openLocation } from '@jbrowse/core/util/io'
3
+ import { unzip } from '@gmod/bgzf-filehandle'
4
+ import PAFAdapter from '../PAFAdapter/PAFAdapter'
5
+ import { parseLineByLine } from '../util'
6
+
7
+ function isGzip(buf: Buffer) {
8
+ return buf[0] === 31 && buf[1] === 139 && buf[2] === 8
9
+ }
10
+
11
+ export default class MashMapAdapter extends PAFAdapter {
12
+ async setupPre(opts?: BaseOptions) {
13
+ const outLoc = openLocation(this.getConf('outLocation'), this.pluginManager)
14
+ const buffer = (await outLoc.readFile(opts)) as Buffer
15
+ const buf = isGzip(buffer) ? await unzip(buffer) : buffer
16
+ return parseLineByLine(buf, parseMashMapLine)
17
+ }
18
+ }
19
+
20
+ function parseMashMapLine(line: string) {
21
+ const fields = line.split(' ')
22
+ if (fields.length < 9) {
23
+ // xref https://github.com/marbl/MashMap/issues/38
24
+ throw new Error('improperly formatted line: ' + line)
25
+ }
26
+ const [qname, , qstart, qend, strand, tname, , tstart, tend, mq] = fields
27
+
28
+ return {
29
+ tname,
30
+ tstart: +tstart,
31
+ tend: +tend,
32
+ qname,
33
+ qstart: +qstart,
34
+ qend: +qend,
35
+ strand: strand === '-' ? -1 : 1,
36
+ extra: {
37
+ mappingQual: +mq,
38
+ },
39
+ }
40
+ }
@@ -0,0 +1,51 @@
1
+ import { ConfigurationSchema } from '@jbrowse/core/configuration'
2
+
3
+ /**
4
+ * #config MashMapAdapter
5
+ */
6
+ function x() {} // eslint-disable-line @typescript-eslint/no-unused-vars
7
+
8
+ const MashMapAdapter = ConfigurationSchema(
9
+ 'MashMapAdapter',
10
+ {
11
+ /**
12
+ * #slot
13
+ */
14
+ assemblyNames: {
15
+ type: 'stringArray',
16
+ defaultValue: [],
17
+ description:
18
+ 'Target is the first value in the array, query is the second',
19
+ },
20
+
21
+ /**
22
+ * #slot
23
+ */
24
+ targetAssembly: {
25
+ type: 'string',
26
+ defaultValue: '',
27
+ description: 'Alternative to assemblyNames array: the target assembly',
28
+ },
29
+ /**
30
+ * #slot
31
+ */
32
+ queryAssembly: {
33
+ type: 'string',
34
+ defaultValue: '',
35
+ description: 'Alternative to assemblyNames array: the query assembly',
36
+ },
37
+ /**
38
+ * #slot
39
+ */
40
+ outLocation: {
41
+ type: 'fileLocation',
42
+ defaultValue: {
43
+ uri: '/path/to/mashmap.out',
44
+ locationType: 'UriLocation',
45
+ },
46
+ },
47
+ },
48
+ { explicitlyTyped: true },
49
+ )
50
+
51
+ export default MashMapAdapter
@@ -0,0 +1,18 @@
1
+ import PluginManager from '@jbrowse/core/PluginManager'
2
+ import AdapterType from '@jbrowse/core/pluggableElementTypes/AdapterType'
3
+ import configSchema from './configSchema'
4
+
5
+ export default (pluginManager: PluginManager) => {
6
+ pluginManager.addAdapterType(
7
+ () =>
8
+ new AdapterType({
9
+ name: 'MashMapAdapter',
10
+ displayName: 'MashMap adapter',
11
+ configSchema,
12
+ adapterMetadata: {
13
+ hiddenFromGUI: true,
14
+ },
15
+ getAdapterClass: () => import('./MashMapAdapter').then(r => r.default),
16
+ }),
17
+ )
18
+ }
@@ -0,0 +1,37 @@
1
+ import { toArray } from 'rxjs/operators'
2
+ import { firstValueFrom } from 'rxjs'
3
+ import Adapter from './PAFAdapter'
4
+ import MyConfigSchema from './configSchema'
5
+
6
+ test('adapter can fetch features from peach_grape.paf', async () => {
7
+ const adapter = new Adapter(
8
+ MyConfigSchema.create({
9
+ pafLocation: {
10
+ localPath: require.resolve('./test_data/peach_grape.paf'),
11
+ locationType: 'LocalPathLocation',
12
+ },
13
+ assemblyNames: ['peach', 'grape'],
14
+ }),
15
+ )
16
+
17
+ const features1 = adapter.getFeatures({
18
+ refName: 'Pp01',
19
+ start: 0,
20
+ end: 200000,
21
+ assemblyName: 'peach',
22
+ })
23
+
24
+ const features2 = adapter.getFeatures({
25
+ refName: 'chr1',
26
+ start: 0,
27
+ end: 200000,
28
+ assemblyName: 'grape',
29
+ })
30
+
31
+ const fa1 = await firstValueFrom(features1.pipe(toArray()))
32
+ const fa2 = await firstValueFrom(features2.pipe(toArray()))
33
+ expect(fa1.length).toBe(11)
34
+ expect(fa2.length).toBe(5)
35
+ expect(fa1[0].get('refName')).toBe('Pp01')
36
+ expect(fa2[0].get('refName')).toBe('chr1')
37
+ })
@@ -0,0 +1,181 @@
1
+ import {
2
+ BaseFeatureDataAdapter,
3
+ BaseOptions,
4
+ } from '@jbrowse/core/data_adapters/BaseAdapter'
5
+ import { Region } from '@jbrowse/core/util/types'
6
+ import { doesIntersect2 } from '@jbrowse/core/util/range'
7
+ import { openLocation } from '@jbrowse/core/util/io'
8
+ import { ObservableCreate } from '@jbrowse/core/util/rxjs'
9
+ import { Feature } from '@jbrowse/core/util'
10
+ import {
11
+ AnyConfigurationModel,
12
+ readConfObject,
13
+ } from '@jbrowse/core/configuration'
14
+ import { unzip } from '@gmod/bgzf-filehandle'
15
+ import { MismatchParser } from '@jbrowse/plugin-alignments'
16
+
17
+ // locals
18
+ import SyntenyFeature from './SyntenyFeature'
19
+ import { isGzip, parseLineByLine } from '../util'
20
+ import {
21
+ getWeightedMeans,
22
+ flipCigar,
23
+ swapIndelCigar,
24
+ parsePAFLine,
25
+ PAFRecord,
26
+ } from './util'
27
+
28
+ const { parseCigar } = MismatchParser
29
+
30
+ interface PAFOptions extends BaseOptions {
31
+ config?: AnyConfigurationModel
32
+ }
33
+
34
+ export default class PAFAdapter extends BaseFeatureDataAdapter {
35
+ private setupP?: Promise<PAFRecord[]>
36
+
37
+ public static capabilities = ['getFeatures', 'getRefNames']
38
+
39
+ async setup(opts?: BaseOptions) {
40
+ if (!this.setupP) {
41
+ this.setupP = this.setupPre(opts).catch(e => {
42
+ this.setupP = undefined
43
+ throw e
44
+ })
45
+ }
46
+ return this.setupP
47
+ }
48
+
49
+ async setupPre(opts?: BaseOptions) {
50
+ const pm = this.pluginManager
51
+ const pafLocation = openLocation(this.getConf('pafLocation'), pm)
52
+ const buffer = (await pafLocation.readFile(opts)) as Buffer
53
+ const buf = isGzip(buffer) ? await unzip(buffer) : buffer
54
+ return parseLineByLine(buf, parsePAFLine)
55
+ }
56
+
57
+ async hasDataForRefName() {
58
+ // determining this properly is basically a call to getFeatures
59
+ // so is not really that important, and has to be true or else
60
+ // getFeatures is never called (BaseAdapter filters it out)
61
+ return true
62
+ }
63
+
64
+ getAssemblyNames() {
65
+ const assemblyNames = this.getConf('assemblyNames') as string[]
66
+ if (assemblyNames.length === 0) {
67
+ const query = this.getConf('queryAssembly') as string
68
+ const target = this.getConf('targetAssembly') as string
69
+ return [query, target]
70
+ }
71
+ return assemblyNames
72
+ }
73
+
74
+ async getRefNames(opts: BaseOptions = {}) {
75
+ // @ts-expect-error
76
+ const r1 = opts.regions?.[0].assemblyName
77
+ const feats = await this.setup(opts)
78
+
79
+ const idx = this.getAssemblyNames().indexOf(r1)
80
+ if (idx !== -1) {
81
+ const set = new Set<string>()
82
+ for (const feat of feats) {
83
+ set.add(idx === 0 ? feat.qname : feat.tname)
84
+ }
85
+ return [...set]
86
+ }
87
+ console.warn('Unable to do ref renaming on adapter')
88
+ return []
89
+ }
90
+
91
+ getFeatures(query: Region, opts: PAFOptions = {}) {
92
+ return ObservableCreate<Feature>(async observer => {
93
+ let pafRecords = await this.setup(opts)
94
+ const { config } = opts
95
+
96
+ // note: this is not the adapter config, it is responding to a display
97
+ // setting passed in via the opts parameter
98
+ if (config && readConfObject(config, 'colorBy') === 'meanQueryIdentity') {
99
+ pafRecords = getWeightedMeans(pafRecords)
100
+ }
101
+ const assemblyNames = this.getAssemblyNames()
102
+
103
+ // The index of the assembly name in the query list corresponds to the
104
+ // adapter in the subadapters list
105
+ const index = assemblyNames.indexOf(query.assemblyName)
106
+ const { start: qstart, end: qend, refName: qref, assemblyName } = query
107
+ if (index === -1) {
108
+ console.warn(`${assemblyName} not found in this adapter`)
109
+ observer.complete()
110
+ }
111
+
112
+ for (let i = 0; i < pafRecords.length; i++) {
113
+ const r = pafRecords[i]
114
+ let start = 0
115
+ let end = 0
116
+ let refName = ''
117
+ let mateName = ''
118
+ let mateStart = 0
119
+ let mateEnd = 0
120
+ const flip = index === 0
121
+ const assemblyName = assemblyNames[+!flip]
122
+ if (index === 0) {
123
+ start = r.qstart
124
+ end = r.qend
125
+ refName = r.qname
126
+ mateName = r.tname
127
+ mateStart = r.tstart
128
+ mateEnd = r.tend
129
+ } else {
130
+ start = r.tstart
131
+ end = r.tend
132
+ refName = r.tname
133
+ mateName = r.qname
134
+ mateStart = r.qstart
135
+ mateEnd = r.qend
136
+ }
137
+ const { extra, strand } = r
138
+ if (refName === qref && doesIntersect2(qstart, qend, start, end)) {
139
+ const { numMatches = 0, blockLen = 1, cg, ...rest } = extra
140
+
141
+ let CIGAR = extra.cg
142
+ if (extra.cg) {
143
+ if (flip && strand === -1) {
144
+ CIGAR = flipCigar(parseCigar(extra.cg)).join('')
145
+ } else if (flip) {
146
+ CIGAR = swapIndelCigar(extra.cg)
147
+ }
148
+ }
149
+
150
+ observer.next(
151
+ new SyntenyFeature({
152
+ uniqueId: i + assemblyName,
153
+ assemblyName,
154
+ start,
155
+ end,
156
+ type: 'match',
157
+ refName,
158
+ strand,
159
+ ...rest,
160
+ CIGAR,
161
+ syntenyId: i,
162
+ identity: numMatches / blockLen,
163
+ numMatches,
164
+ blockLen,
165
+ mate: {
166
+ start: mateStart,
167
+ end: mateEnd,
168
+ refName: mateName,
169
+ assemblyName: assemblyNames[+flip],
170
+ },
171
+ }),
172
+ )
173
+ }
174
+ }
175
+
176
+ observer.complete()
177
+ })
178
+ }
179
+
180
+ freeResources(/* { query } */): void {}
181
+ }
@@ -0,0 +1,15 @@
1
+ import { SimpleFeature } from '@jbrowse/core/util'
2
+ import { MismatchParser } from '@jbrowse/plugin-alignments'
3
+
4
+ // locals
5
+ const { getMismatches } = MismatchParser
6
+
7
+ export default class SyntenyFeature extends SimpleFeature {
8
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
9
+ get(arg: string): any {
10
+ if (arg === 'mismatches') {
11
+ return getMismatches(this.get('CIGAR'))
12
+ }
13
+ return super.get(arg)
14
+ }
15
+ }