react-msaview 4.6.0 → 4.8.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 (93) hide show
  1. package/bundle/index.js +99 -99
  2. package/bundle/index.js.LICENSE.txt +6 -6
  3. package/bundle/index.js.map +1 -1
  4. package/dist/__snapshots__/parseAsn1.test.js.snap +2400 -0
  5. package/dist/components/header/HeaderInfoArea.js +3 -4
  6. package/dist/components/header/HeaderInfoArea.js.map +1 -1
  7. package/dist/components/import/ImportForm.js +6 -2
  8. package/dist/components/import/ImportForm.js.map +1 -1
  9. package/dist/components/import/util.d.ts +1 -1
  10. package/dist/components/import/util.js +4 -1
  11. package/dist/components/import/util.js.map +1 -1
  12. package/dist/components/msa/renderBoxFeatureCanvasBlock.js +7 -2
  13. package/dist/components/msa/renderBoxFeatureCanvasBlock.js.map +1 -1
  14. package/dist/components/msa/renderMSABlock.js.map +1 -1
  15. package/dist/components/tree/renderTreeCanvas.js +10 -8
  16. package/dist/components/tree/renderTreeCanvas.js.map +1 -1
  17. package/dist/model.d.ts +153 -16
  18. package/dist/model.js +97 -29
  19. package/dist/model.js.map +1 -1
  20. package/dist/rowCoordinateCalculations.d.ts +69 -9
  21. package/dist/rowCoordinateCalculations.js +118 -46
  22. package/dist/rowCoordinateCalculations.js.map +1 -1
  23. package/dist/rowCoordinateCalculations.test.js +152 -52
  24. package/dist/rowCoordinateCalculations.test.js.map +1 -1
  25. package/dist/seqPosToGlobalCol.d.ts +19 -0
  26. package/dist/seqPosToGlobalCol.js +34 -0
  27. package/dist/seqPosToGlobalCol.js.map +1 -0
  28. package/dist/seqPosToGlobalCol.test.js +60 -0
  29. package/dist/seqPosToGlobalCol.test.js.map +1 -0
  30. package/dist/util.d.ts +1 -2
  31. package/dist/util.js +0 -9
  32. package/dist/util.js.map +1 -1
  33. package/dist/version.d.ts +1 -1
  34. package/dist/version.js +1 -1
  35. package/package.json +7 -9
  36. package/src/components/header/HeaderInfoArea.tsx +2 -5
  37. package/src/components/import/ImportForm.tsx +6 -1
  38. package/src/components/import/util.ts +4 -0
  39. package/src/components/msa/renderBoxFeatureCanvasBlock.ts +7 -2
  40. package/src/components/msa/renderMSABlock.ts +5 -1
  41. package/src/components/tree/renderTreeCanvas.ts +11 -9
  42. package/src/declare.d.ts +0 -1
  43. package/src/model.ts +122 -42
  44. package/src/rowCoordinateCalculations.test.ts +167 -74
  45. package/src/rowCoordinateCalculations.ts +138 -63
  46. package/src/seqPosToGlobalCol.test.ts +71 -0
  47. package/src/seqPosToGlobalCol.ts +40 -0
  48. package/src/util.ts +1 -19
  49. package/src/version.ts +1 -1
  50. package/dist/parseGFF.d.ts +0 -10
  51. package/dist/parseGFF.js +0 -31
  52. package/dist/parseGFF.js.map +0 -1
  53. package/dist/parseNewick.d.ts +0 -60
  54. package/dist/parseNewick.js +0 -95
  55. package/dist/parseNewick.js.map +0 -1
  56. package/dist/parsers/A3mMSA.d.ts +0 -43
  57. package/dist/parsers/A3mMSA.js +0 -277
  58. package/dist/parsers/A3mMSA.js.map +0 -1
  59. package/dist/parsers/A3mMSA.test.js +0 -138
  60. package/dist/parsers/A3mMSA.test.js.map +0 -1
  61. package/dist/parsers/ClustalMSA.d.ts +0 -30
  62. package/dist/parsers/ClustalMSA.js +0 -55
  63. package/dist/parsers/ClustalMSA.js.map +0 -1
  64. package/dist/parsers/EmfMSA.d.ts +0 -27
  65. package/dist/parsers/EmfMSA.js +0 -53
  66. package/dist/parsers/EmfMSA.js.map +0 -1
  67. package/dist/parsers/EmfTree.d.ts +0 -5
  68. package/dist/parsers/EmfTree.js +0 -8
  69. package/dist/parsers/EmfTree.js.map +0 -1
  70. package/dist/parsers/FastaMSA.d.ts +0 -19
  71. package/dist/parsers/FastaMSA.js +0 -69
  72. package/dist/parsers/FastaMSA.js.map +0 -1
  73. package/dist/parsers/StockholmMSA.d.ts +0 -68
  74. package/dist/parsers/StockholmMSA.js +0 -107
  75. package/dist/parsers/StockholmMSA.js.map +0 -1
  76. package/dist/seqCoordToRowSpecificGlobalCoord.d.ts +0 -4
  77. package/dist/seqCoordToRowSpecificGlobalCoord.js +0 -19
  78. package/dist/seqCoordToRowSpecificGlobalCoord.js.map +0 -1
  79. package/dist/seqCoordToRowSpecificGlobalCoord.test.d.ts +0 -1
  80. package/dist/seqCoordToRowSpecificGlobalCoord.test.js +0 -42
  81. package/dist/seqCoordToRowSpecificGlobalCoord.test.js.map +0 -1
  82. package/src/parseGFF.ts +0 -34
  83. package/src/parseNewick.ts +0 -94
  84. package/src/parsers/A3mMSA.test.ts +0 -164
  85. package/src/parsers/A3mMSA.ts +0 -321
  86. package/src/parsers/ClustalMSA.ts +0 -69
  87. package/src/parsers/EmfMSA.ts +0 -67
  88. package/src/parsers/EmfTree.ts +0 -9
  89. package/src/parsers/FastaMSA.ts +0 -82
  90. package/src/parsers/StockholmMSA.ts +0 -140
  91. package/src/seqCoordToRowSpecificGlobalCoord.test.ts +0 -53
  92. package/src/seqCoordToRowSpecificGlobalCoord.ts +0 -25
  93. /package/dist/{parsers/A3mMSA.test.d.ts → seqPosToGlobalCol.test.d.ts} +0 -0
@@ -1,69 +0,0 @@
1
- import { parse } from 'clustal-js'
2
-
3
- import type { NodeWithIds } from '../types'
4
-
5
- export default class ClustalMSA {
6
- private MSA: ReturnType<typeof parse>
7
-
8
- constructor(text: string) {
9
- this.MSA = parse(text)
10
- }
11
-
12
- getMSA() {
13
- return this.MSA
14
- }
15
-
16
- getRow(name: string): string {
17
- return this.MSA.alns.find(aln => aln.id === name)?.seq || ''
18
- }
19
-
20
- getWidth() {
21
- return this.MSA.alns[0]!.seq.length
22
- }
23
-
24
- getRowData() {
25
- return undefined
26
- }
27
-
28
- getHeader() {
29
- return this.MSA.header
30
- }
31
-
32
- getNames() {
33
- return this.MSA.alns.map(aln => aln.id)
34
- }
35
-
36
- getStructures() {
37
- return {}
38
- }
39
-
40
- get alignmentNames() {
41
- return []
42
- }
43
-
44
- getTree(): NodeWithIds {
45
- return {
46
- id: 'root',
47
- name: 'root',
48
- noTree: true,
49
- children: this.getNames()
50
- .filter((name): name is string => name !== undefined)
51
- .map(name => ({
52
- id: name,
53
- name,
54
- children: [],
55
- })),
56
- }
57
- }
58
-
59
- get seqConsensus() {
60
- return this.MSA.consensus
61
- }
62
- get secondaryStructureConsensus() {
63
- return undefined
64
- }
65
-
66
- get tracks() {
67
- return []
68
- }
69
- }
@@ -1,67 +0,0 @@
1
- import { parseEmfAln } from 'emf-js'
2
-
3
- import type { NodeWithIds } from '../types'
4
-
5
- export default class EmfMSA {
6
- private MSA: ReturnType<typeof parseEmfAln>
7
-
8
- constructor(text: string) {
9
- this.MSA = parseEmfAln(text)
10
- }
11
-
12
- getMSA() {
13
- return this.MSA
14
- }
15
-
16
- getRow(name: string): string {
17
- return this.MSA.find(aln => aln.protein === name)?.seq || ''
18
- }
19
-
20
- getWidth() {
21
- return this.MSA[0]!.seq.length
22
- }
23
-
24
- getRowData() {
25
- return undefined
26
- }
27
-
28
- getHeader() {
29
- return ''
30
- }
31
-
32
- getNames() {
33
- return this.MSA.map(aln => aln.protein)
34
- }
35
-
36
- getStructures() {
37
- return {}
38
- }
39
-
40
- get alignmentNames() {
41
- return []
42
- }
43
-
44
- getTree(): NodeWithIds {
45
- return {
46
- id: 'root',
47
- name: 'root',
48
- noTree: true,
49
- children: this.getNames().map(name => ({
50
- id: name,
51
- name,
52
- children: [],
53
- })),
54
- }
55
- }
56
-
57
- get seqConsensus() {
58
- return undefined
59
- }
60
- get secondaryStructureConsensus() {
61
- return undefined
62
- }
63
-
64
- get tracks() {
65
- return []
66
- }
67
- }
@@ -1,9 +0,0 @@
1
- import { parseEmfTree } from 'emf-js'
2
-
3
- export default class EmfTree {
4
- data: ReturnType<typeof parseEmfTree>
5
-
6
- constructor(text: string) {
7
- this.data = parseEmfTree(text)
8
- }
9
- }
@@ -1,82 +0,0 @@
1
- import type { NodeWithIds } from '../types'
2
-
3
- export default class FastaMSA {
4
- private MSA: { seqdata: Record<string, string> }
5
-
6
- constructor(text: string) {
7
- const seqdata: Record<string, string> = {}
8
- for (const entry of text.split('>')) {
9
- if (!/\S/.test(entry)) {
10
- continue
11
- }
12
- const newlineIdx = entry.indexOf('\n')
13
- if (newlineIdx === -1) {
14
- continue
15
- }
16
- const defLine = entry.slice(0, newlineIdx)
17
- const spaceIdx = defLine.indexOf(' ')
18
- const id = spaceIdx === -1 ? defLine : defLine.slice(0, spaceIdx)
19
- if (id) {
20
- seqdata[id] = entry.slice(newlineIdx + 1).replaceAll(/\s/g, '')
21
- }
22
- }
23
- this.MSA = { seqdata }
24
- }
25
-
26
- getMSA() {
27
- return this.MSA
28
- }
29
-
30
- getRowData() {
31
- return undefined
32
- }
33
-
34
- getNames() {
35
- return Object.keys(this.MSA.seqdata)
36
- }
37
-
38
- getRow(name: string) {
39
- return this.MSA.seqdata[name] || ''
40
- }
41
-
42
- getWidth() {
43
- const name = Object.keys(this.MSA.seqdata)[0]!
44
- return this.getRow(name).length
45
- }
46
-
47
- getStructures() {
48
- return {}
49
- }
50
-
51
- get alignmentNames() {
52
- return []
53
- }
54
-
55
- getHeader() {
56
- return {}
57
- }
58
-
59
- getTree(): NodeWithIds {
60
- return {
61
- id: 'root',
62
- name: 'root',
63
- noTree: true,
64
- children: this.getNames().map(name => ({
65
- id: name,
66
- children: [],
67
- name,
68
- })),
69
- }
70
- }
71
-
72
- get seqConsensus() {
73
- return undefined
74
- }
75
- get secondaryStructureConsensus() {
76
- return undefined
77
- }
78
-
79
- get tracks() {
80
- return []
81
- }
82
- }
@@ -1,140 +0,0 @@
1
- import Stockholm from 'stockholm-js'
2
-
3
- import parseNewick from '../parseNewick'
4
- import { generateNodeIds } from '../util'
5
-
6
- import type { NodeWithIds } from '../types'
7
-
8
- interface StockholmEntry {
9
- gf: {
10
- DE?: string[]
11
- NH?: string[]
12
- }
13
- gs?: {
14
- AC: Record<string, string>
15
- DR?: Record<string, string>
16
- }
17
- gc?: {
18
- SS_cons?: string
19
- seq_cons?: string
20
- }
21
- seqdata: Record<string, string>
22
- }
23
-
24
- export default class StockholmMSA {
25
- private data: StockholmEntry[]
26
- private MSA: StockholmEntry
27
-
28
- constructor(text: string, currentAlignment: number) {
29
- const res = Stockholm.parseAll(text)
30
- this.data = res
31
- this.MSA = res[currentAlignment]
32
- }
33
-
34
- getMSA() {
35
- return this.MSA
36
- }
37
-
38
- getRow(name: string) {
39
- return this.MSA.seqdata[name] || ''
40
- }
41
-
42
- getWidth() {
43
- const name = Object.keys(this.MSA.seqdata)[0]!
44
- return this.getRow(name).length
45
- }
46
-
47
- get alignmentNames() {
48
- return this.data.map((aln, idx) => aln.gf.DE?.[0] || `Alignment ${idx + 1}`)
49
- }
50
-
51
- getHeader() {
52
- return {
53
- General: this.MSA.gf,
54
- Accessions: this.MSA.gs?.AC,
55
- Dbxref: this.MSA.gs?.DR,
56
- }
57
- }
58
-
59
- getRowData(rowName: string) {
60
- return {
61
- name: rowName,
62
- accession: this.MSA.gs?.AC[rowName],
63
- dbxref: this.MSA.gs?.DR?.[rowName],
64
- }
65
- }
66
-
67
- getNames() {
68
- return Object.keys(this.MSA.seqdata)
69
- }
70
-
71
- getSeqCoords() {}
72
-
73
- getStructures() {
74
- const pdbRegex = /PDB; +(\S+) +(\S); ([0-9]+)-([0-9]+)/
75
- const ent = this.MSA
76
- const args = Object.entries(ent.gs?.DR || {})
77
- .map(([id, dr]) => [id, pdbRegex.exec(dr)] as const)
78
- .filter((item): item is [string, RegExpExecArray] => !!item[1])
79
- .map(([id, match]) => {
80
- const pdb = match[1]!.toLowerCase()
81
- const chain = match[2]!
82
- const startPos = +match[3]!
83
- const endPos = +match[4]!
84
- return { id, pdb, chain, startPos, endPos }
85
- })
86
-
87
- const ret = {} as Record<string, Omit<(typeof args)[0], 'id'>[]>
88
- for (const entry of args) {
89
- const { id, ...rest } = entry
90
- if (!ret[id]) {
91
- ret[id] = []
92
- }
93
- ret[id].push(rest)
94
- }
95
- return ret
96
- }
97
-
98
- getTree(): NodeWithIds {
99
- const tree = this.MSA.gf.NH?.[0]
100
- return tree
101
- ? generateNodeIds(parseNewick(tree))
102
- : {
103
- id: 'root',
104
- name: 'root',
105
- noTree: true,
106
- children: this.getNames().map(name => ({
107
- id: name,
108
- children: [],
109
- name,
110
- })),
111
- }
112
- }
113
-
114
- get seqConsensus() {
115
- return this.MSA.gc?.seq_cons
116
- }
117
- get secondaryStructureConsensus() {
118
- return this.MSA.gc?.SS_cons
119
- }
120
-
121
- get tracks() {
122
- return [
123
- {
124
- id: 'seqConsensus',
125
- name: 'Sequence consensus',
126
- data: this.seqConsensus,
127
- customColorScheme: {},
128
- },
129
- {
130
- id: 'secondaryStruct',
131
- name: 'Secondary-structure',
132
- data: this.secondaryStructureConsensus,
133
- customColorScheme: {
134
- '>': 'pink',
135
- '<': 'lightblue',
136
- },
137
- },
138
- ]
139
- }
140
- }
@@ -1,53 +0,0 @@
1
- import { describe, expect, test } from 'vitest'
2
-
3
- import { seqCoordToRowSpecificGlobalCoord } from './seqCoordToRowSpecificGlobalCoord'
4
-
5
- describe('seqCoordToRowSpecificGlobalCoord', () => {
6
- test('converts sequence coordinate to global coordinate with no gaps', () => {
7
- const row = 'ATGCATGC'
8
- expect(seqCoordToRowSpecificGlobalCoord({ row, position: 3 })).toBe(3)
9
- expect(seqCoordToRowSpecificGlobalCoord({ row, position: 0 })).toBe(0)
10
- expect(seqCoordToRowSpecificGlobalCoord({ row, position: 8 })).toBe(8)
11
- })
12
-
13
- test('converts sequence coordinate to global coordinate with gaps', () => {
14
- const row = 'A-TG-CA-TGC'
15
- // A(0) -(1) T(2) G(3) -(4) C(5) A(6) -(7) T(8) G(9) C(10)
16
- // Sequence positions: A(0) T(1) G(2) C(3) A(4) T(5) G(6) C(7)
17
-
18
- // Position 0 (first A) -> Global index 0
19
- expect(seqCoordToRowSpecificGlobalCoord({ row, position: 0 })).toBe(0)
20
-
21
- // Position 1 (T after first gap) -> Global index 2
22
- expect(seqCoordToRowSpecificGlobalCoord({ row, position: 1 })).toBe(2)
23
-
24
- // Position 3 (C after second gap) -> Global index 5
25
- expect(seqCoordToRowSpecificGlobalCoord({ row, position: 3 })).toBe(5)
26
-
27
- // Position 5 (T after third gap) -> Global index 8
28
- expect(seqCoordToRowSpecificGlobalCoord({ row, position: 5 })).toBe(8)
29
-
30
- // Position 8 (end of sequence) -> Global index 11
31
- expect(seqCoordToRowSpecificGlobalCoord({ row, position: 8 })).toBe(11)
32
- })
33
-
34
- test('handles empty row', () => {
35
- expect(seqCoordToRowSpecificGlobalCoord({ row: '', position: 0 })).toBe(0)
36
- })
37
-
38
- test('handles row with only gaps', () => {
39
- const row = '---..--'
40
- expect(seqCoordToRowSpecificGlobalCoord({ row, position: 0 })).toBe(0)
41
- })
42
-
43
- test('handles mixed gap characters', () => {
44
- const row = 'A-.G-C.'
45
- // A(0) -(1) .(2) G(3) -(4) C(5) .(6)
46
- // Sequence positions: A(0) G(1) C(2)
47
-
48
- expect(seqCoordToRowSpecificGlobalCoord({ row, position: 0 })).toBe(0)
49
- expect(seqCoordToRowSpecificGlobalCoord({ row, position: 1 })).toBe(3)
50
- expect(seqCoordToRowSpecificGlobalCoord({ row, position: 2 })).toBe(5)
51
- expect(seqCoordToRowSpecificGlobalCoord({ row, position: 3 })).toBe(7)
52
- })
53
- })
@@ -1,25 +0,0 @@
1
- import { isBlank } from './util'
2
-
3
- export function seqCoordToRowSpecificGlobalCoord({
4
- row,
5
- position,
6
- }: {
7
- row: string
8
- position: number
9
- }) {
10
- let k = 0
11
- let i = 0
12
- // Find the position-th non-gap character
13
- while (i < row.length) {
14
- if (!isBlank(row[i])) {
15
- if (k === position) {
16
- return i
17
- }
18
- k++
19
- }
20
- i++
21
- }
22
- // If position is 0 and we didn't find any non-gap character, return 0
23
- // Otherwise return i (which is row.length at this point)
24
- return position === 0 ? 0 : i
25
- }