jbrowse-plugin-mafviewer 1.0.8 → 1.1.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 (126) hide show
  1. package/README.md +54 -20
  2. package/dist/{TaffyAdapter/TaffyAdapter.d.ts → BgzipTaffyAdapter/BgzipTaffyAdapter.d.ts} +11 -7
  3. package/dist/BgzipTaffyAdapter/BgzipTaffyAdapter.js +197 -0
  4. package/dist/BgzipTaffyAdapter/BgzipTaffyAdapter.js.map +1 -0
  5. package/dist/{TaffyAdapter → BgzipTaffyAdapter}/configSchema.d.ts +14 -1
  6. package/dist/{TaffyAdapter → BgzipTaffyAdapter}/configSchema.js +21 -6
  7. package/dist/BgzipTaffyAdapter/configSchema.js.map +1 -0
  8. package/dist/BgzipTaffyAdapter/index.d.ts +2 -0
  9. package/dist/BgzipTaffyAdapter/index.js +11 -0
  10. package/dist/BgzipTaffyAdapter/index.js.map +1 -0
  11. package/dist/BgzipTaffyAdapter/rowInstructions.d.ts +35 -0
  12. package/dist/BgzipTaffyAdapter/rowInstructions.js +55 -0
  13. package/dist/BgzipTaffyAdapter/rowInstructions.js.map +1 -0
  14. package/dist/BgzipTaffyAdapter/types.d.ts +13 -0
  15. package/dist/BgzipTaffyAdapter/types.js +2 -0
  16. package/dist/BgzipTaffyAdapter/types.js.map +1 -0
  17. package/dist/BgzipTaffyAdapter/virtualOffset.d.ts +8 -0
  18. package/dist/BgzipTaffyAdapter/virtualOffset.js +23 -0
  19. package/dist/BgzipTaffyAdapter/virtualOffset.js.map +1 -0
  20. package/dist/BigMafAdapter/BigMafAdapter.js +1 -1
  21. package/dist/BigMafAdapter/BigMafAdapter.js.map +1 -1
  22. package/dist/BigMafAdapter/configSchema.d.ts +11 -0
  23. package/dist/BigMafAdapter/configSchema.js +11 -0
  24. package/dist/BigMafAdapter/configSchema.js.map +1 -1
  25. package/dist/BigMafAdapter/index.js +1 -1
  26. package/dist/BigMafAdapter/index.js.map +1 -1
  27. package/dist/LinearMafDisplay/components/ColorLegend.js +10 -6
  28. package/dist/LinearMafDisplay/components/ColorLegend.js.map +1 -1
  29. package/dist/LinearMafDisplay/components/ReactComponent.js +39 -4
  30. package/dist/LinearMafDisplay/components/ReactComponent.js.map +1 -1
  31. package/dist/LinearMafDisplay/components/SetRowHeight.js +7 -7
  32. package/dist/LinearMafDisplay/components/SetRowHeight.js.map +1 -1
  33. package/dist/LinearMafDisplay/components/SvgWrapper.d.ts +8 -0
  34. package/dist/LinearMafDisplay/components/SvgWrapper.js +21 -0
  35. package/dist/LinearMafDisplay/components/SvgWrapper.js.map +1 -0
  36. package/dist/LinearMafDisplay/components/Tree.d.ts +5 -0
  37. package/dist/LinearMafDisplay/components/Tree.js +22 -0
  38. package/dist/LinearMafDisplay/components/Tree.js.map +1 -0
  39. package/dist/LinearMafDisplay/components/YScaleBars.d.ts +0 -1
  40. package/dist/LinearMafDisplay/components/YScaleBars.js +6 -27
  41. package/dist/LinearMafDisplay/components/YScaleBars.js.map +1 -1
  42. package/dist/LinearMafDisplay/components/util.d.ts +1 -0
  43. package/dist/LinearMafDisplay/components/util.js +8 -0
  44. package/dist/LinearMafDisplay/components/util.js.map +1 -0
  45. package/dist/LinearMafDisplay/index.js +1 -1
  46. package/dist/LinearMafDisplay/index.js.map +1 -1
  47. package/dist/LinearMafDisplay/renderSvg.js +1 -0
  48. package/dist/LinearMafDisplay/renderSvg.js.map +1 -1
  49. package/dist/LinearMafDisplay/stateModel.d.ts +76 -14
  50. package/dist/LinearMafDisplay/stateModel.js +118 -18
  51. package/dist/LinearMafDisplay/stateModel.js.map +1 -1
  52. package/dist/LinearMafDisplay/types.d.ts +17 -0
  53. package/dist/LinearMafDisplay/types.js +16 -0
  54. package/dist/LinearMafDisplay/types.js.map +1 -0
  55. package/dist/LinearMafRenderer/LinearMafRenderer.d.ts +3 -3
  56. package/dist/LinearMafRenderer/LinearMafRenderer.js +11 -9
  57. package/dist/LinearMafRenderer/LinearMafRenderer.js.map +1 -1
  58. package/dist/LinearMafRenderer/components/ReactComponent.js +1 -1
  59. package/dist/LinearMafRenderer/components/ReactComponent.js.map +1 -1
  60. package/dist/LinearMafRenderer/index.js +1 -1
  61. package/dist/LinearMafRenderer/index.js.map +1 -1
  62. package/dist/MafAddTrackWorkflow/AddTrackWorkflow.js +42 -25
  63. package/dist/MafAddTrackWorkflow/AddTrackWorkflow.js.map +1 -1
  64. package/dist/MafRPC/index.d.ts +16 -0
  65. package/dist/MafRPC/index.js +19 -0
  66. package/dist/MafRPC/index.js.map +1 -0
  67. package/dist/MafTabixAdapter/MafTabixAdapter.d.ts +8 -0
  68. package/dist/MafTabixAdapter/MafTabixAdapter.js +18 -19
  69. package/dist/MafTabixAdapter/MafTabixAdapter.js.map +1 -1
  70. package/dist/MafTabixAdapter/configSchema.d.ts +17 -0
  71. package/dist/MafTabixAdapter/configSchema.js +17 -1
  72. package/dist/MafTabixAdapter/configSchema.js.map +1 -1
  73. package/dist/MafTabixAdapter/index.js +1 -1
  74. package/dist/MafTabixAdapter/index.js.map +1 -1
  75. package/dist/MafTrack/index.js.map +1 -1
  76. package/dist/index.js +6 -4
  77. package/dist/index.js.map +1 -1
  78. package/dist/jbrowse-plugin-mafviewer.umd.production.min.js +65 -4
  79. package/dist/jbrowse-plugin-mafviewer.umd.production.min.js.map +4 -4
  80. package/dist/parseNewick.d.ts +60 -0
  81. package/dist/parseNewick.js +95 -0
  82. package/dist/parseNewick.js.map +1 -0
  83. package/dist/util.d.ts +9 -0
  84. package/dist/util.js +9 -0
  85. package/dist/util.js.map +1 -0
  86. package/package.json +18 -5
  87. package/src/BgzipTaffyAdapter/BgzipTaffyAdapter.ts +227 -0
  88. package/src/{TaffyAdapter → BgzipTaffyAdapter}/configSchema.ts +21 -6
  89. package/src/{TaffyAdapter → BgzipTaffyAdapter}/index.ts +5 -4
  90. package/src/BgzipTaffyAdapter/rowInstructions.ts +91 -0
  91. package/src/BgzipTaffyAdapter/types.ts +16 -0
  92. package/src/BgzipTaffyAdapter/virtualOffset.ts +29 -0
  93. package/src/BigMafAdapter/BigMafAdapter.ts +11 -11
  94. package/src/BigMafAdapter/configSchema.ts +11 -0
  95. package/src/BigMafAdapter/index.ts +2 -1
  96. package/src/LinearMafDisplay/components/ColorLegend.tsx +36 -25
  97. package/src/LinearMafDisplay/components/ReactComponent.tsx +68 -3
  98. package/src/LinearMafDisplay/components/SetRowHeight.tsx +6 -5
  99. package/src/LinearMafDisplay/components/SvgWrapper.tsx +39 -0
  100. package/src/LinearMafDisplay/components/Tree.tsx +33 -0
  101. package/src/LinearMafDisplay/components/YScaleBars.tsx +8 -43
  102. package/src/LinearMafDisplay/components/util.ts +7 -0
  103. package/src/LinearMafDisplay/index.ts +2 -1
  104. package/src/LinearMafDisplay/renderSvg.tsx +2 -1
  105. package/src/LinearMafDisplay/stateModel.ts +139 -18
  106. package/src/LinearMafDisplay/types.ts +41 -0
  107. package/src/LinearMafRenderer/LinearMafRenderer.ts +13 -10
  108. package/src/LinearMafRenderer/components/ReactComponent.tsx +2 -1
  109. package/src/LinearMafRenderer/index.ts +2 -1
  110. package/src/MafAddTrackWorkflow/AddTrackWorkflow.tsx +109 -65
  111. package/src/MafRPC/index.ts +39 -0
  112. package/src/MafTabixAdapter/MafTabixAdapter.ts +31 -25
  113. package/src/MafTabixAdapter/configSchema.ts +17 -1
  114. package/src/MafTabixAdapter/index.ts +2 -1
  115. package/src/MafTrack/index.ts +1 -0
  116. package/src/index.ts +6 -4
  117. package/src/parseNewick.ts +94 -0
  118. package/src/util.ts +11 -0
  119. package/LICENSE +0 -201
  120. package/dist/TaffyAdapter/TaffyAdapter.js +0 -89
  121. package/dist/TaffyAdapter/TaffyAdapter.js.map +0 -1
  122. package/dist/TaffyAdapter/configSchema.js.map +0 -1
  123. package/dist/TaffyAdapter/index.d.ts +0 -2
  124. package/dist/TaffyAdapter/index.js +0 -11
  125. package/dist/TaffyAdapter/index.js.map +0 -1
  126. package/src/TaffyAdapter/TaffyAdapter.ts +0 -112
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Newick format parser in JavaScript.
3
+ *
4
+ * Copyright (c) Jason Davies 2010.
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ * of this software and associated documentation files (the "Software"), to deal
8
+ * in the Software without restriction, including without limitation the rights
9
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ * copies of the Software, and to permit persons to whom the Software is
11
+ * furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice shall be included in
14
+ * all copies or substantial portions of the Software.
15
+ *
16
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
+ * THE SOFTWARE.
23
+ *
24
+ * Example tree (from http://en.wikipedia.org/wiki/Newick_format):
25
+ *
26
+ * +--0.1--A
27
+ * F-----0.2-----B +-------0.3----C
28
+ * +------------------0.5-----E
29
+ * +---------0.4------D
30
+ *
31
+ * Newick format:
32
+ * (A:0.1,B:0.2,(C:0.3,D:0.4)E:0.5)F;
33
+ *
34
+ * Converted to JSON:
35
+ * {
36
+ * name: "F",
37
+ * children: [
38
+ * {name: "A", length: 0.1},
39
+ * {name: "B", length: 0.2},
40
+ * {
41
+ * name: "E",
42
+ * length: 0.5,
43
+ * children: [
44
+ * {name: "C", length: 0.3},
45
+ * {name: "D", length: 0.4}
46
+ * ]
47
+ * }
48
+ * ]
49
+ * }
50
+ *
51
+ * Converted to JSON, but with no names or lengths:
52
+ * {
53
+ * children: [
54
+ * {}, {}, {
55
+ * children: [{}, {}]
56
+ * }
57
+ * ]
58
+ * }
59
+ */
60
+ export default function parseNewick(s: string): Record<string, any>;
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Newick format parser in JavaScript.
3
+ *
4
+ * Copyright (c) Jason Davies 2010.
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ * of this software and associated documentation files (the "Software"), to deal
8
+ * in the Software without restriction, including without limitation the rights
9
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ * copies of the Software, and to permit persons to whom the Software is
11
+ * furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice shall be included in
14
+ * all copies or substantial portions of the Software.
15
+ *
16
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
+ * THE SOFTWARE.
23
+ *
24
+ * Example tree (from http://en.wikipedia.org/wiki/Newick_format):
25
+ *
26
+ * +--0.1--A
27
+ * F-----0.2-----B +-------0.3----C
28
+ * +------------------0.5-----E
29
+ * +---------0.4------D
30
+ *
31
+ * Newick format:
32
+ * (A:0.1,B:0.2,(C:0.3,D:0.4)E:0.5)F;
33
+ *
34
+ * Converted to JSON:
35
+ * {
36
+ * name: "F",
37
+ * children: [
38
+ * {name: "A", length: 0.1},
39
+ * {name: "B", length: 0.2},
40
+ * {
41
+ * name: "E",
42
+ * length: 0.5,
43
+ * children: [
44
+ * {name: "C", length: 0.3},
45
+ * {name: "D", length: 0.4}
46
+ * ]
47
+ * }
48
+ * ]
49
+ * }
50
+ *
51
+ * Converted to JSON, but with no names or lengths:
52
+ * {
53
+ * children: [
54
+ * {}, {}, {
55
+ * children: [{}, {}]
56
+ * }
57
+ * ]
58
+ * }
59
+ */
60
+ export default function parseNewick(s) {
61
+ const ancestors = [];
62
+ let tree = {};
63
+ const tokens = s.split(/\s*(;|\(|\)|,|:)\s*/);
64
+ for (let i = 0; i < tokens.length; i++) {
65
+ const token = tokens[i];
66
+ const subtree = {};
67
+ switch (token) {
68
+ case '(': // new children
69
+ tree.children = [subtree];
70
+ ancestors.push(tree);
71
+ tree = subtree;
72
+ break;
73
+ case ',': // another branch
74
+ ancestors.at(-1)?.children.push(subtree);
75
+ tree = subtree;
76
+ break;
77
+ case ')': // optional name next
78
+ tree = ancestors.pop();
79
+ break;
80
+ case ':': // optional length next
81
+ break;
82
+ default: {
83
+ const x = tokens[i - 1];
84
+ if (x === ')' || x === '(' || x === ',') {
85
+ tree.name = token;
86
+ }
87
+ else if (x === ':') {
88
+ tree.length = Number.parseFloat(token);
89
+ }
90
+ }
91
+ }
92
+ }
93
+ return tree;
94
+ }
95
+ //# sourceMappingURL=parseNewick.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parseNewick.js","sourceRoot":"","sources":["../src/parseNewick.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0DG;AACH,MAAM,CAAC,OAAO,UAAU,WAAW,CAAC,CAAS;IAC3C,MAAM,SAAS,GAAG,EAAE,CAAA;IAEpB,IAAI,IAAI,GAAG,EAAyB,CAAA;IACpC,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAA;IAC7C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACvC,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAE,CAAA;QACxB,MAAM,OAAO,GAAG,EAAE,CAAA;QAClB,QAAQ,KAAK,EAAE,CAAC;YACd,KAAK,GAAG,EAAE,eAAe;gBACvB,IAAI,CAAC,QAAQ,GAAG,CAAC,OAAO,CAAC,CAAA;gBACzB,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;gBACpB,IAAI,GAAG,OAAO,CAAA;gBACd,MAAK;YACP,KAAK,GAAG,EAAE,iBAAiB;gBACzB,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;gBACxC,IAAI,GAAG,OAAO,CAAA;gBACd,MAAK;YACP,KAAK,GAAG,EAAE,qBAAqB;gBAC7B,IAAI,GAAG,SAAS,CAAC,GAAG,EAAG,CAAA;gBACvB,MAAK;YACP,KAAK,GAAG,EAAE,uBAAuB;gBAC/B,MAAK;YACP,OAAO,CAAC,CAAC,CAAC;gBACR,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,CAAE,CAAA;gBACxB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;oBACxC,IAAI,CAAC,IAAI,GAAG,KAAK,CAAA;gBACnB,CAAC;qBAAM,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;oBACrB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,CAAA;gBACxC,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC"}
package/dist/util.d.ts ADDED
@@ -0,0 +1,9 @@
1
+ export declare function normalize(r: string[] | {
2
+ id: string;
3
+ label: string;
4
+ color?: string;
5
+ }[]): {
6
+ id: string;
7
+ label: string;
8
+ color?: string;
9
+ }[];
package/dist/util.js ADDED
@@ -0,0 +1,9 @@
1
+ function isStrs(array) {
2
+ return typeof array[0] === 'string';
3
+ }
4
+ export function normalize(r) {
5
+ return isStrs(r)
6
+ ? r.map(elt => ({ id: elt, label: elt, color: undefined }))
7
+ : r;
8
+ }
9
+ //# sourceMappingURL=util.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"util.js","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"AAAA,SAAS,MAAM,CAAC,KAAgB;IAC9B,OAAO,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,QAAQ,CAAA;AACrC,CAAC;AAED,MAAM,UAAU,SAAS,CACvB,CAA6D;IAE7D,OAAO,MAAM,CAAC,CAAC,CAAC;QACd,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;QAC3D,CAAC,CAAC,CAAC,CAAA;AACP,CAAC"}
package/package.json CHANGED
@@ -1,5 +1,6 @@
1
1
  {
2
- "version": "1.0.8",
2
+ "version": "1.1.1",
3
+ "license": "MIT",
3
4
  "name": "jbrowse-plugin-mafviewer",
4
5
  "keywords": [
5
6
  "jbrowse",
@@ -15,6 +16,7 @@
15
16
  "scripts": {
16
17
  "clean": "rimraf dist",
17
18
  "start": "node esbuild.mjs",
19
+ "format": "prettier --write .",
18
20
  "prebuild": "npm run clean",
19
21
  "build": "tsc && NODE_ENV=production node esbuild.mjs",
20
22
  "lint": "eslint --report-unused-disable-directives --max-warnings 0",
@@ -26,12 +28,14 @@
26
28
  "@babel/preset-react": "^7.10.4",
27
29
  "@emotion/react": "^11.10.4",
28
30
  "@fal-works/esbuild-plugin-global-externals": "^2.1.2",
29
- "@jbrowse/core": "^2.6.1",
30
- "@jbrowse/plugin-data-management": "^2.7.1",
31
- "@jbrowse/plugin-linear-genome-view": "^2.7.1",
31
+ "@jbrowse/core": "^3.0.1",
32
+ "@jbrowse/plugin-data-management": "^3.0.1",
33
+ "@jbrowse/plugin-linear-genome-view": "^3.0.1",
32
34
  "@mui/material": "^6.2.0",
33
35
  "@mui/system": "^6.2.0",
34
36
  "@mui/x-data-grid": "^7.2.0",
37
+ "@types/d3-array": "^3.2.1",
38
+ "@types/d3-hierarchy": "^3.1.7",
35
39
  "@types/node": "^22.10.2",
36
40
  "@types/react": "^19.0.1",
37
41
  "@typescript-eslint/eslint-plugin": "^8.18.0",
@@ -39,12 +43,13 @@
39
43
  "chalk": "^5.3.0",
40
44
  "esbuild": "^0.24.0",
41
45
  "eslint": "^9.17.0",
46
+ "eslint-plugin-import": "^2.31.0",
42
47
  "eslint-plugin-react": "^7.20.3",
43
48
  "eslint-plugin-react-hooks": "^5.1.0",
44
49
  "eslint-plugin-unicorn": "^56.0.1",
45
50
  "mobx": "^6.0.0",
46
51
  "mobx-react": "^9.0.1",
47
- "mobx-state-tree": "5.4.1",
52
+ "mobx-state-tree": "^5.4.1",
48
53
  "prettier": "^3.4.2",
49
54
  "pretty-bytes": "^6.1.1",
50
55
  "react": "^19.0.0",
@@ -55,5 +60,13 @@
55
60
  "tss-react": "^4.8.6",
56
61
  "typescript": "^5.1.6",
57
62
  "typescript-eslint": "^8.18.0"
63
+ },
64
+ "dependencies": {
65
+ "@gmod/bgzf-filehandle": "^2.0.4",
66
+ "buffer": "^6.0.3",
67
+ "d3-array": "^3.2.4",
68
+ "d3-hierarchy": "^3.1.2",
69
+ "generic-filehandle2": "^1.0.0",
70
+ "long": "^5.2.3"
58
71
  }
59
72
  }
@@ -0,0 +1,227 @@
1
+ import { unzip } from '@gmod/bgzf-filehandle'
2
+ import { BaseFeatureDataAdapter } from '@jbrowse/core/data_adapters/BaseAdapter'
3
+ import { Feature, Region, SimpleFeature } from '@jbrowse/core/util'
4
+ import { openLocation } from '@jbrowse/core/util/io'
5
+ import { ObservableCreate } from '@jbrowse/core/util/rxjs'
6
+ import Long from 'long'
7
+
8
+ import VirtualOffset from './virtualOffset'
9
+ import parseNewick from '../parseNewick'
10
+ import { normalize } from '../util'
11
+ import { parseRowInstructions } from './rowInstructions'
12
+
13
+ import type { IndexData, OrganismRecord } from './types'
14
+ interface Entry {
15
+ type: string
16
+ row: number
17
+ asm: string
18
+ ref: string
19
+ start: number
20
+ strand: number
21
+ length: number
22
+ }
23
+ export default class BgzipTaffyAdapter extends BaseFeatureDataAdapter {
24
+ public setupP?: Promise<IndexData>
25
+
26
+ async getRefNames() {
27
+ const data = await this.setup()
28
+ return Object.keys(data)
29
+ }
30
+
31
+ setup() {
32
+ if (!this.setupP) {
33
+ this.setupP = this.readTaiFile().catch((e: unknown) => {
34
+ this.setupP = undefined
35
+ throw e
36
+ })
37
+ }
38
+ return this.setupP
39
+ }
40
+
41
+ async readTaiFile() {
42
+ const text = await openLocation(this.getConf('taiLocation')).readFile(
43
+ 'utf8',
44
+ )
45
+ const lines = text
46
+ .split('\n')
47
+ .map(f => f.trim())
48
+ .filter(line => !!line)
49
+ const entries = {} as IndexData
50
+ let lastChr = ''
51
+ let lastChrStart = 0
52
+ let lastRawVirtualOffset = 0
53
+ for (const line of lines) {
54
+ const [chr, chrStart, virtualOffset] = line.split('\t')
55
+ const relativizedVirtualOffset = lastRawVirtualOffset + +virtualOffset!
56
+ const currChr = chr === '*' ? lastChr : chr!.split('.').at(-1)!
57
+
58
+ // bgzip TAF files store virtual offsets in plaintext in the TAI file
59
+ // these virtualoffsets are 64bit values, so the long library is needed
60
+ // to accurately do the bit manipulations needed
61
+ const x = Long.fromNumber(relativizedVirtualOffset)
62
+ const y = x.shiftRightUnsigned(16)
63
+ const z = x.and(0xffff)
64
+ const voff = new VirtualOffset(y.toNumber(), z.toNumber())
65
+
66
+ if (!entries[currChr]) {
67
+ entries[currChr] = []
68
+ lastChr = ''
69
+ lastChrStart = 0
70
+ lastRawVirtualOffset = 0
71
+ }
72
+ const currStart = +chrStart! + lastChrStart
73
+ entries[currChr].push({
74
+ chrStart: currStart,
75
+ virtualOffset: voff,
76
+ })
77
+ lastChr = currChr
78
+ lastChrStart = currStart
79
+ lastRawVirtualOffset = relativizedVirtualOffset
80
+ }
81
+ return entries
82
+ }
83
+
84
+ getFeatures(query: Region) {
85
+ return ObservableCreate<Feature>(async observer => {
86
+ try {
87
+ const lines = await this.getLines(query)
88
+ const alignments = {} as Record<string, OrganismRecord>
89
+
90
+ const k = lines.length
91
+ const data = [] as Entry[]
92
+ let a0: any
93
+ for (let j = 0; j < k; j++) {
94
+ const line = lines[j]!
95
+ if (line) {
96
+ const [lineData, rowInstructions] = line.split(' ; ')
97
+ if (rowInstructions) {
98
+ for (const ins of parseRowInstructions(rowInstructions)) {
99
+ if (ins.type === 'i') {
100
+ data.splice(ins.row, 0, ins)
101
+ if (!alignments[ins.asm]) {
102
+ alignments[ins.asm] = {
103
+ start: ins.start,
104
+ strand: ins.strand,
105
+ srcSize: ins.length,
106
+ chr: ins.ref,
107
+ data: '',
108
+ }
109
+ }
110
+ const e = alignments[ins.asm]!
111
+ e.data += ' '.repeat(Math.max(0, j - e.data.length)) // catch it up
112
+ } else if (ins.type === 's') {
113
+ if (!alignments[ins.asm]) {
114
+ alignments[ins.asm] = {
115
+ start: ins.start,
116
+ strand: ins.strand,
117
+ srcSize: ins.length,
118
+ chr: ins.ref,
119
+ data: '',
120
+ }
121
+ }
122
+ const e = alignments[ins.asm]!
123
+ e.data += ' '.repeat(Math.max(0, j - e.data.length)) // catch it up
124
+ data[ins.row] = ins
125
+ } else if (ins.type === 'd') {
126
+ data.splice(ins.row, 1)
127
+ }
128
+
129
+ // no gaps for now(?)
130
+ // else if (ins.type === 'g') {
131
+ // }
132
+ // else if (ins.type === 'G') {
133
+ // }
134
+ }
135
+ if (!a0) {
136
+ a0 = data[0]
137
+ }
138
+ }
139
+ const lineLen = lineData!.length
140
+ for (let i = 0; i < lineLen; i++) {
141
+ const letter = lineData![i]
142
+ const r = data[i]!
143
+ alignments[r.asm]!.data += letter
144
+ }
145
+ }
146
+ }
147
+ if (a0) {
148
+ const row0 = alignments[a0.asm]!
149
+
150
+ // see
151
+ // https://github.com/ComparativeGenomicsToolkit/taffy/blob/f5a5354/docs/taffy_utilities.md#referenced-based-maftaf-and-indexing
152
+ // for the significance of row[0]:
153
+ //
154
+ // "An anchor line in TAF is a column from which all sequence
155
+ // coordinates can be deduced without scanning backwards to previous
156
+ // lines "
157
+ observer.next(
158
+ new SimpleFeature({
159
+ uniqueId: `${row0.start}-${row0.data.length}`,
160
+ refName: query.refName,
161
+ start: row0.start,
162
+ end: row0.start + row0.data.length,
163
+ strand: row0.strand,
164
+ alignments,
165
+ seq: row0.data,
166
+ }),
167
+ )
168
+ }
169
+ observer.complete()
170
+ } catch (e) {
171
+ observer.error(e)
172
+ }
173
+ })
174
+ }
175
+
176
+ async getSamples(_query: Region) {
177
+ const nhLoc = this.getConf('nhLocation')
178
+ const nh =
179
+ nhLoc.uri === '/path/to/my.nh'
180
+ ? undefined
181
+ : await openLocation(nhLoc).readFile('utf8')
182
+
183
+ // TODO: we may need to resolve the exact set of rows in the visible region
184
+ // here
185
+ return {
186
+ samples: normalize(this.getConf('samples')),
187
+ tree: nh ? parseNewick(nh) : undefined,
188
+ }
189
+ }
190
+
191
+ async getLines(query: Region) {
192
+ const byteRanges = await this.setup()
193
+ const file = openLocation(this.getConf('tafGzLocation'))
194
+
195
+ const decoder = new TextDecoder('utf8')
196
+ const records = byteRanges[query.refName]
197
+ if (records) {
198
+ let firstEntry = records[0]
199
+ let nextEntry
200
+ for (let i = 0; i < records.length; i++) {
201
+ if (records[i]!.chrStart >= query.start) {
202
+ // we use i-1 for firstEntry because the current record is "greater
203
+ // than the query start", we go backwards one record to make sure to
204
+ // cover up until the query start. we use i+1 to ensure we get at
205
+ // least one block in the case that i=0
206
+ firstEntry = records[Math.max(i - 1, 0)]
207
+ nextEntry = records[i + 1]
208
+ break
209
+ }
210
+ }
211
+ if (firstEntry && nextEntry) {
212
+ const response = await file.read(
213
+ nextEntry.virtualOffset.blockPosition -
214
+ firstEntry.virtualOffset.blockPosition,
215
+ firstEntry.virtualOffset.blockPosition,
216
+ )
217
+ const buffer = await unzip(response)
218
+ return decoder
219
+ .decode(buffer.slice(firstEntry.virtualOffset.dataPosition))
220
+ .split('\n')
221
+ }
222
+ }
223
+ return []
224
+ }
225
+
226
+ freeResources(): void {}
227
+ }
@@ -1,13 +1,13 @@
1
1
  import { ConfigurationSchema } from '@jbrowse/core/configuration'
2
2
 
3
3
  /**
4
- * #config TaffyAdapter
5
- * used to configure Taffy adapter
4
+ * #config BgzipTaffyAdapter
5
+ * used to configure BgzipTaffy adapter
6
6
  */
7
7
  function x() {} // eslint-disable-line @typescript-eslint/no-unused-vars
8
8
 
9
9
  const configSchema = ConfigurationSchema(
10
- 'TaffyAdapter',
10
+ 'BgzipTaffyAdapter',
11
11
  {
12
12
  /**
13
13
  * #slot
@@ -20,8 +20,9 @@ const configSchema = ConfigurationSchema(
20
20
  /**
21
21
  * #slot
22
22
  */
23
- tafLocation: {
23
+ tafGzLocation: {
24
24
  type: 'fileLocation',
25
+ description: 'bgzip taffy file',
25
26
  defaultValue: {
26
27
  uri: '/path/to/my.taf',
27
28
  locationType: 'UriLocation',
@@ -32,13 +33,27 @@ const configSchema = ConfigurationSchema(
32
33
  */
33
34
  taiLocation: {
34
35
  type: 'fileLocation',
36
+ description: 'taffy index',
35
37
  defaultValue: {
36
- uri: '/path/to/my.taf.tai',
38
+ uri: '/path/to/my.taf.gz.tai',
37
39
  locationType: 'UriLocation',
38
40
  },
39
41
  },
42
+ /**
43
+ * #slot
44
+ */
45
+ nhLocation: {
46
+ type: 'fileLocation',
47
+ description: 'newick tree',
48
+ defaultValue: {
49
+ uri: '/path/to/my.nh',
50
+ locationType: 'UriLocation',
51
+ },
52
+ },
53
+ },
54
+ {
55
+ explicitlyTyped: true,
40
56
  },
41
- { explicitlyTyped: true },
42
57
  )
43
58
 
44
59
  export default configSchema
@@ -1,14 +1,15 @@
1
1
  import PluginManager from '@jbrowse/core/PluginManager'
2
2
  import { AdapterType } from '@jbrowse/core/pluggableElementTypes'
3
+
4
+ import BgzipTaffyAdapter from './BgzipTaffyAdapter'
3
5
  import configSchema from './configSchema'
4
- import TaffyAdapter from './TaffyAdapter'
5
6
 
6
- export default function TaffyAdapterF(pluginManager: PluginManager) {
7
+ export default function BgzipTaffyAdapterF(pluginManager: PluginManager) {
7
8
  return pluginManager.addAdapterType(
8
9
  () =>
9
10
  new AdapterType({
10
- name: 'TaffyAdapter',
11
- AdapterClass: TaffyAdapter,
11
+ name: 'BgzipTaffyAdapter',
12
+ AdapterClass: BgzipTaffyAdapter,
12
13
  configSchema,
13
14
  }),
14
15
  )
@@ -0,0 +1,91 @@
1
+ interface RowInsert {
2
+ type: 'i'
3
+ row: number
4
+ asm: string
5
+ ref: string
6
+ start: number
7
+ strand: number
8
+ length: number
9
+ }
10
+ interface RowSubstitute {
11
+ type: 's'
12
+ row: number
13
+ asm: string
14
+ ref: string
15
+ start: number
16
+ strand: number
17
+ length: number
18
+ }
19
+ interface RowDelete {
20
+ type: 'd'
21
+ row: number
22
+ }
23
+ interface RowGap {
24
+ type: 'g'
25
+ row: number
26
+ gapLen: number
27
+ }
28
+ interface RowGapSubstring {
29
+ type: 'G'
30
+ row: number
31
+ gapSubstring: string
32
+ }
33
+ type RowInstruction =
34
+ | RowInsert
35
+ | RowDelete
36
+ | RowGap
37
+ | RowGapSubstring
38
+ | RowSubstitute
39
+
40
+ export function parseRowInstructions(meta: string) {
41
+ const ret = meta.split(' ')
42
+ const rows = [] as RowInstruction[]
43
+
44
+ for (let i = 0; i < ret.length; ) {
45
+ const type = ret[i++]
46
+ if (type === 'i') {
47
+ const row = +ret[i++]!
48
+ const [asm, ref] = ret[i++]!.split('.')
49
+ rows.push({
50
+ type,
51
+ row,
52
+ asm: asm!,
53
+ ref: ref!,
54
+ start: +ret[i++]!,
55
+ strand: ret[i++] === '-' ? -1 : 1,
56
+ length: +ret[i++]!,
57
+ })
58
+ }
59
+ if (type === 's') {
60
+ const row = +ret[i++]!
61
+ const [asm, ref] = ret[i++]!.split('.')
62
+ rows.push({
63
+ type,
64
+ row,
65
+ asm: asm!,
66
+ ref: ref!,
67
+ start: +ret[i++]!,
68
+ strand: ret[i++] === '-' ? -1 : 1,
69
+ length: +ret[i++]!,
70
+ })
71
+ } else if (type === 'd') {
72
+ rows.push({
73
+ type,
74
+ row: +ret[i++]!,
75
+ })
76
+ } else if (type === 'g') {
77
+ rows.push({
78
+ type,
79
+ row: +ret[i++]!,
80
+ gapLen: +ret[i++]!,
81
+ })
82
+ } else if (type === 'G') {
83
+ rows.push({
84
+ type,
85
+ row: +ret[i++]!,
86
+ gapSubstring: ret[i++]!,
87
+ })
88
+ }
89
+ }
90
+ return rows
91
+ }
@@ -0,0 +1,16 @@
1
+ import VirtualOffset from './virtualOffset'
2
+
3
+ export interface OrganismRecord {
4
+ chr: string
5
+ start: number
6
+ srcSize: number
7
+ strand: number
8
+ data: string
9
+ }
10
+
11
+ export interface ByteRange {
12
+ chrStart: number
13
+ virtualOffset: VirtualOffset
14
+ }
15
+
16
+ export type IndexData = Record<string, ByteRange[]>
@@ -0,0 +1,29 @@
1
+ export default class VirtualOffset {
2
+ public blockPosition: number
3
+ public dataPosition: number
4
+ constructor(blockPosition: number, dataPosition: number) {
5
+ this.blockPosition = blockPosition // < offset of the compressed data block
6
+ this.dataPosition = dataPosition // < offset into the uncompressed data
7
+ }
8
+
9
+ toString() {
10
+ return `${this.blockPosition}:${this.dataPosition}`
11
+ }
12
+
13
+ compareTo(b: VirtualOffset) {
14
+ return (
15
+ this.blockPosition - b.blockPosition || this.dataPosition - b.dataPosition
16
+ )
17
+ }
18
+ }
19
+ export function fromBytes(bytes: Uint8Array, offset = 0) {
20
+ return new VirtualOffset(
21
+ bytes[offset + 7]! * 0x10000000000 +
22
+ bytes[offset + 6]! * 0x100000000 +
23
+ bytes[offset + 5]! * 0x1000000 +
24
+ bytes[offset + 4]! * 0x10000 +
25
+ bytes[offset + 3]! * 0x100 +
26
+ bytes[offset + 2]!,
27
+ (bytes[offset + 1]! << 8) | bytes[offset]!,
28
+ )
29
+ }