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.
- package/README.md +54 -20
- package/dist/{TaffyAdapter/TaffyAdapter.d.ts → BgzipTaffyAdapter/BgzipTaffyAdapter.d.ts} +11 -7
- package/dist/BgzipTaffyAdapter/BgzipTaffyAdapter.js +197 -0
- package/dist/BgzipTaffyAdapter/BgzipTaffyAdapter.js.map +1 -0
- package/dist/{TaffyAdapter → BgzipTaffyAdapter}/configSchema.d.ts +14 -1
- package/dist/{TaffyAdapter → BgzipTaffyAdapter}/configSchema.js +21 -6
- package/dist/BgzipTaffyAdapter/configSchema.js.map +1 -0
- package/dist/BgzipTaffyAdapter/index.d.ts +2 -0
- package/dist/BgzipTaffyAdapter/index.js +11 -0
- package/dist/BgzipTaffyAdapter/index.js.map +1 -0
- package/dist/BgzipTaffyAdapter/rowInstructions.d.ts +35 -0
- package/dist/BgzipTaffyAdapter/rowInstructions.js +55 -0
- package/dist/BgzipTaffyAdapter/rowInstructions.js.map +1 -0
- package/dist/BgzipTaffyAdapter/types.d.ts +13 -0
- package/dist/BgzipTaffyAdapter/types.js +2 -0
- package/dist/BgzipTaffyAdapter/types.js.map +1 -0
- package/dist/BgzipTaffyAdapter/virtualOffset.d.ts +8 -0
- package/dist/BgzipTaffyAdapter/virtualOffset.js +23 -0
- package/dist/BgzipTaffyAdapter/virtualOffset.js.map +1 -0
- package/dist/BigMafAdapter/BigMafAdapter.js +1 -1
- package/dist/BigMafAdapter/BigMafAdapter.js.map +1 -1
- package/dist/BigMafAdapter/configSchema.d.ts +11 -0
- package/dist/BigMafAdapter/configSchema.js +11 -0
- package/dist/BigMafAdapter/configSchema.js.map +1 -1
- package/dist/BigMafAdapter/index.js +1 -1
- package/dist/BigMafAdapter/index.js.map +1 -1
- package/dist/LinearMafDisplay/components/ColorLegend.js +10 -6
- package/dist/LinearMafDisplay/components/ColorLegend.js.map +1 -1
- package/dist/LinearMafDisplay/components/ReactComponent.js +39 -4
- package/dist/LinearMafDisplay/components/ReactComponent.js.map +1 -1
- package/dist/LinearMafDisplay/components/SetRowHeight.js +7 -7
- package/dist/LinearMafDisplay/components/SetRowHeight.js.map +1 -1
- package/dist/LinearMafDisplay/components/SvgWrapper.d.ts +8 -0
- package/dist/LinearMafDisplay/components/SvgWrapper.js +21 -0
- package/dist/LinearMafDisplay/components/SvgWrapper.js.map +1 -0
- package/dist/LinearMafDisplay/components/Tree.d.ts +5 -0
- package/dist/LinearMafDisplay/components/Tree.js +22 -0
- package/dist/LinearMafDisplay/components/Tree.js.map +1 -0
- package/dist/LinearMafDisplay/components/YScaleBars.d.ts +0 -1
- package/dist/LinearMafDisplay/components/YScaleBars.js +6 -27
- package/dist/LinearMafDisplay/components/YScaleBars.js.map +1 -1
- package/dist/LinearMafDisplay/components/util.d.ts +1 -0
- package/dist/LinearMafDisplay/components/util.js +8 -0
- package/dist/LinearMafDisplay/components/util.js.map +1 -0
- package/dist/LinearMafDisplay/index.js +1 -1
- package/dist/LinearMafDisplay/index.js.map +1 -1
- package/dist/LinearMafDisplay/renderSvg.js +1 -0
- package/dist/LinearMafDisplay/renderSvg.js.map +1 -1
- package/dist/LinearMafDisplay/stateModel.d.ts +76 -14
- package/dist/LinearMafDisplay/stateModel.js +118 -18
- package/dist/LinearMafDisplay/stateModel.js.map +1 -1
- package/dist/LinearMafDisplay/types.d.ts +17 -0
- package/dist/LinearMafDisplay/types.js +16 -0
- package/dist/LinearMafDisplay/types.js.map +1 -0
- package/dist/LinearMafRenderer/LinearMafRenderer.d.ts +3 -3
- package/dist/LinearMafRenderer/LinearMafRenderer.js +11 -9
- package/dist/LinearMafRenderer/LinearMafRenderer.js.map +1 -1
- package/dist/LinearMafRenderer/components/ReactComponent.js +1 -1
- package/dist/LinearMafRenderer/components/ReactComponent.js.map +1 -1
- package/dist/LinearMafRenderer/index.js +1 -1
- package/dist/LinearMafRenderer/index.js.map +1 -1
- package/dist/MafAddTrackWorkflow/AddTrackWorkflow.js +42 -25
- package/dist/MafAddTrackWorkflow/AddTrackWorkflow.js.map +1 -1
- package/dist/MafRPC/index.d.ts +16 -0
- package/dist/MafRPC/index.js +19 -0
- package/dist/MafRPC/index.js.map +1 -0
- package/dist/MafTabixAdapter/MafTabixAdapter.d.ts +8 -0
- package/dist/MafTabixAdapter/MafTabixAdapter.js +18 -19
- package/dist/MafTabixAdapter/MafTabixAdapter.js.map +1 -1
- package/dist/MafTabixAdapter/configSchema.d.ts +17 -0
- package/dist/MafTabixAdapter/configSchema.js +17 -1
- package/dist/MafTabixAdapter/configSchema.js.map +1 -1
- package/dist/MafTabixAdapter/index.js +1 -1
- package/dist/MafTabixAdapter/index.js.map +1 -1
- package/dist/MafTrack/index.js.map +1 -1
- package/dist/index.js +6 -4
- package/dist/index.js.map +1 -1
- package/dist/jbrowse-plugin-mafviewer.umd.production.min.js +65 -4
- package/dist/jbrowse-plugin-mafviewer.umd.production.min.js.map +4 -4
- package/dist/parseNewick.d.ts +60 -0
- package/dist/parseNewick.js +95 -0
- package/dist/parseNewick.js.map +1 -0
- package/dist/util.d.ts +9 -0
- package/dist/util.js +9 -0
- package/dist/util.js.map +1 -0
- package/package.json +18 -5
- package/src/BgzipTaffyAdapter/BgzipTaffyAdapter.ts +227 -0
- package/src/{TaffyAdapter → BgzipTaffyAdapter}/configSchema.ts +21 -6
- package/src/{TaffyAdapter → BgzipTaffyAdapter}/index.ts +5 -4
- package/src/BgzipTaffyAdapter/rowInstructions.ts +91 -0
- package/src/BgzipTaffyAdapter/types.ts +16 -0
- package/src/BgzipTaffyAdapter/virtualOffset.ts +29 -0
- package/src/BigMafAdapter/BigMafAdapter.ts +11 -11
- package/src/BigMafAdapter/configSchema.ts +11 -0
- package/src/BigMafAdapter/index.ts +2 -1
- package/src/LinearMafDisplay/components/ColorLegend.tsx +36 -25
- package/src/LinearMafDisplay/components/ReactComponent.tsx +68 -3
- package/src/LinearMafDisplay/components/SetRowHeight.tsx +6 -5
- package/src/LinearMafDisplay/components/SvgWrapper.tsx +39 -0
- package/src/LinearMafDisplay/components/Tree.tsx +33 -0
- package/src/LinearMafDisplay/components/YScaleBars.tsx +8 -43
- package/src/LinearMafDisplay/components/util.ts +7 -0
- package/src/LinearMafDisplay/index.ts +2 -1
- package/src/LinearMafDisplay/renderSvg.tsx +2 -1
- package/src/LinearMafDisplay/stateModel.ts +139 -18
- package/src/LinearMafDisplay/types.ts +41 -0
- package/src/LinearMafRenderer/LinearMafRenderer.ts +13 -10
- package/src/LinearMafRenderer/components/ReactComponent.tsx +2 -1
- package/src/LinearMafRenderer/index.ts +2 -1
- package/src/MafAddTrackWorkflow/AddTrackWorkflow.tsx +109 -65
- package/src/MafRPC/index.ts +39 -0
- package/src/MafTabixAdapter/MafTabixAdapter.ts +31 -25
- package/src/MafTabixAdapter/configSchema.ts +17 -1
- package/src/MafTabixAdapter/index.ts +2 -1
- package/src/MafTrack/index.ts +1 -0
- package/src/index.ts +6 -4
- package/src/parseNewick.ts +94 -0
- package/src/util.ts +11 -0
- package/LICENSE +0 -201
- package/dist/TaffyAdapter/TaffyAdapter.js +0 -89
- package/dist/TaffyAdapter/TaffyAdapter.js.map +0 -1
- package/dist/TaffyAdapter/configSchema.js.map +0 -1
- package/dist/TaffyAdapter/index.d.ts +0 -2
- package/dist/TaffyAdapter/index.js +0 -11
- package/dist/TaffyAdapter/index.js.map +0 -1
- 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
package/dist/util.js
ADDED
package/dist/util.js.map
ADDED
|
@@ -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.
|
|
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": "^
|
|
30
|
-
"@jbrowse/plugin-data-management": "^
|
|
31
|
-
"@jbrowse/plugin-linear-genome-view": "^
|
|
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
|
|
5
|
-
* used to configure
|
|
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
|
-
'
|
|
10
|
+
'BgzipTaffyAdapter',
|
|
11
11
|
{
|
|
12
12
|
/**
|
|
13
13
|
* #slot
|
|
@@ -20,8 +20,9 @@ const configSchema = ConfigurationSchema(
|
|
|
20
20
|
/**
|
|
21
21
|
* #slot
|
|
22
22
|
*/
|
|
23
|
-
|
|
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
|
|
7
|
+
export default function BgzipTaffyAdapterF(pluginManager: PluginManager) {
|
|
7
8
|
return pluginManager.addAdapterType(
|
|
8
9
|
() =>
|
|
9
10
|
new AdapterType({
|
|
10
|
-
name: '
|
|
11
|
-
AdapterClass:
|
|
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
|
+
}
|