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.
- package/bundle/index.js +99 -99
- package/bundle/index.js.LICENSE.txt +6 -6
- package/bundle/index.js.map +1 -1
- package/dist/__snapshots__/parseAsn1.test.js.snap +2400 -0
- package/dist/components/header/HeaderInfoArea.js +3 -4
- package/dist/components/header/HeaderInfoArea.js.map +1 -1
- package/dist/components/import/ImportForm.js +6 -2
- package/dist/components/import/ImportForm.js.map +1 -1
- package/dist/components/import/util.d.ts +1 -1
- package/dist/components/import/util.js +4 -1
- package/dist/components/import/util.js.map +1 -1
- package/dist/components/msa/renderBoxFeatureCanvasBlock.js +7 -2
- package/dist/components/msa/renderBoxFeatureCanvasBlock.js.map +1 -1
- package/dist/components/msa/renderMSABlock.js.map +1 -1
- package/dist/components/tree/renderTreeCanvas.js +10 -8
- package/dist/components/tree/renderTreeCanvas.js.map +1 -1
- package/dist/model.d.ts +153 -16
- package/dist/model.js +97 -29
- package/dist/model.js.map +1 -1
- package/dist/rowCoordinateCalculations.d.ts +69 -9
- package/dist/rowCoordinateCalculations.js +118 -46
- package/dist/rowCoordinateCalculations.js.map +1 -1
- package/dist/rowCoordinateCalculations.test.js +152 -52
- package/dist/rowCoordinateCalculations.test.js.map +1 -1
- package/dist/seqPosToGlobalCol.d.ts +19 -0
- package/dist/seqPosToGlobalCol.js +34 -0
- package/dist/seqPosToGlobalCol.js.map +1 -0
- package/dist/seqPosToGlobalCol.test.js +60 -0
- package/dist/seqPosToGlobalCol.test.js.map +1 -0
- package/dist/util.d.ts +1 -2
- package/dist/util.js +0 -9
- package/dist/util.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +7 -9
- package/src/components/header/HeaderInfoArea.tsx +2 -5
- package/src/components/import/ImportForm.tsx +6 -1
- package/src/components/import/util.ts +4 -0
- package/src/components/msa/renderBoxFeatureCanvasBlock.ts +7 -2
- package/src/components/msa/renderMSABlock.ts +5 -1
- package/src/components/tree/renderTreeCanvas.ts +11 -9
- package/src/declare.d.ts +0 -1
- package/src/model.ts +122 -42
- package/src/rowCoordinateCalculations.test.ts +167 -74
- package/src/rowCoordinateCalculations.ts +138 -63
- package/src/seqPosToGlobalCol.test.ts +71 -0
- package/src/seqPosToGlobalCol.ts +40 -0
- package/src/util.ts +1 -19
- package/src/version.ts +1 -1
- package/dist/parseGFF.d.ts +0 -10
- package/dist/parseGFF.js +0 -31
- package/dist/parseGFF.js.map +0 -1
- package/dist/parseNewick.d.ts +0 -60
- package/dist/parseNewick.js +0 -95
- package/dist/parseNewick.js.map +0 -1
- package/dist/parsers/A3mMSA.d.ts +0 -43
- package/dist/parsers/A3mMSA.js +0 -277
- package/dist/parsers/A3mMSA.js.map +0 -1
- package/dist/parsers/A3mMSA.test.js +0 -138
- package/dist/parsers/A3mMSA.test.js.map +0 -1
- package/dist/parsers/ClustalMSA.d.ts +0 -30
- package/dist/parsers/ClustalMSA.js +0 -55
- package/dist/parsers/ClustalMSA.js.map +0 -1
- package/dist/parsers/EmfMSA.d.ts +0 -27
- package/dist/parsers/EmfMSA.js +0 -53
- package/dist/parsers/EmfMSA.js.map +0 -1
- package/dist/parsers/EmfTree.d.ts +0 -5
- package/dist/parsers/EmfTree.js +0 -8
- package/dist/parsers/EmfTree.js.map +0 -1
- package/dist/parsers/FastaMSA.d.ts +0 -19
- package/dist/parsers/FastaMSA.js +0 -69
- package/dist/parsers/FastaMSA.js.map +0 -1
- package/dist/parsers/StockholmMSA.d.ts +0 -68
- package/dist/parsers/StockholmMSA.js +0 -107
- package/dist/parsers/StockholmMSA.js.map +0 -1
- package/dist/seqCoordToRowSpecificGlobalCoord.d.ts +0 -4
- package/dist/seqCoordToRowSpecificGlobalCoord.js +0 -19
- package/dist/seqCoordToRowSpecificGlobalCoord.js.map +0 -1
- package/dist/seqCoordToRowSpecificGlobalCoord.test.d.ts +0 -1
- package/dist/seqCoordToRowSpecificGlobalCoord.test.js +0 -42
- package/dist/seqCoordToRowSpecificGlobalCoord.test.js.map +0 -1
- package/src/parseGFF.ts +0 -34
- package/src/parseNewick.ts +0 -94
- package/src/parsers/A3mMSA.test.ts +0 -164
- package/src/parsers/A3mMSA.ts +0 -321
- package/src/parsers/ClustalMSA.ts +0 -69
- package/src/parsers/EmfMSA.ts +0 -67
- package/src/parsers/EmfTree.ts +0 -9
- package/src/parsers/FastaMSA.ts +0 -82
- package/src/parsers/StockholmMSA.ts +0 -140
- package/src/seqCoordToRowSpecificGlobalCoord.test.ts +0 -53
- package/src/seqCoordToRowSpecificGlobalCoord.ts +0 -25
- /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
|
-
}
|
package/src/parsers/EmfMSA.ts
DELETED
|
@@ -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
|
-
}
|
package/src/parsers/EmfTree.ts
DELETED
package/src/parsers/FastaMSA.ts
DELETED
|
@@ -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
|
-
}
|
|
File without changes
|