msa-parsers 5.0.7 → 5.0.13
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/dist/gff/gffToInterPro.d.ts +0 -4
- package/dist/gff/gffToInterPro.js +0 -7
- package/dist/gff/gffToInterPro.js.map +1 -1
- package/dist/msa/A3mMSA.d.ts +2 -21
- package/dist/msa/A3mMSA.js +3 -67
- package/dist/msa/A3mMSA.js.map +1 -1
- package/dist/msa/BaseMSA.d.ts +19 -0
- package/dist/{src/msa/EmfMSA.js → msa/BaseMSA.js} +15 -32
- package/dist/msa/BaseMSA.js.map +1 -0
- package/dist/msa/ClustalMSA.d.ts +2 -8
- package/dist/msa/ClustalMSA.js +3 -28
- package/dist/msa/ClustalMSA.js.map +1 -1
- package/dist/msa/EmfMSA.d.ts +2 -9
- package/dist/msa/EmfMSA.js +3 -31
- package/dist/msa/EmfMSA.js.map +1 -1
- package/dist/msa/FastaMSA.d.ts +2 -10
- package/dist/msa/FastaMSA.js +3 -34
- package/dist/msa/FastaMSA.js.map +1 -1
- package/dist/msa/StockholmMSA.d.ts +2 -2
- package/dist/msa/StockholmMSA.js +18 -34
- package/dist/msa/StockholmMSA.js.map +1 -1
- package/package.json +7 -2
- package/src/gff/gffToInterPro.ts +0 -11
- package/src/msa/A3mMSA.ts +3 -76
- package/src/msa/BaseMSA.ts +49 -0
- package/src/msa/ClustalMSA.ts +3 -34
- package/src/msa/EmfMSA.ts +3 -38
- package/src/msa/FastaMSA.ts +3 -42
- package/src/msa/StockholmMSA.ts +18 -39
- package/dist/src/gff/gffToInterPro.d.ts +0 -20
- package/dist/src/gff/gffToInterPro.js +0 -83
- package/dist/src/gff/gffToInterPro.js.map +0 -1
- package/dist/src/gff/gffToInterPro.test.d.ts +0 -1
- package/dist/src/gff/gffToInterPro.test.js +0 -181
- package/dist/src/gff/gffToInterPro.test.js.map +0 -1
- package/dist/src/gff/index.d.ts +0 -3
- package/dist/src/gff/index.js +0 -4
- package/dist/src/gff/index.js.map +0 -1
- package/dist/src/gff/interProToGFF.d.ts +0 -9
- package/dist/src/gff/interProToGFF.js +0 -48
- package/dist/src/gff/interProToGFF.js.map +0 -1
- package/dist/src/gff/interProToGFF.test.d.ts +0 -1
- package/dist/src/gff/interProToGFF.test.js +0 -189
- package/dist/src/gff/interProToGFF.test.js.map +0 -1
- package/dist/src/gff/parseGFF.d.ts +0 -2
- package/dist/src/gff/parseGFF.js +0 -41
- package/dist/src/gff/parseGFF.js.map +0 -1
- package/dist/src/gff/parseGFF.test.d.ts +0 -1
- package/dist/src/gff/parseGFF.test.js +0 -92
- package/dist/src/gff/parseGFF.test.js.map +0 -1
- package/dist/src/index.d.ts +0 -5
- package/dist/src/index.js +0 -9
- package/dist/src/index.js.map +0 -1
- package/dist/src/msa/A3mMSA.d.ts +0 -33
- package/dist/src/msa/A3mMSA.js +0 -282
- package/dist/src/msa/A3mMSA.js.map +0 -1
- package/dist/src/msa/A3mMSA.test.d.ts +0 -1
- package/dist/src/msa/A3mMSA.test.js +0 -261
- package/dist/src/msa/A3mMSA.test.js.map +0 -1
- package/dist/src/msa/ClustalMSA.d.ts +0 -30
- package/dist/src/msa/ClustalMSA.js +0 -53
- package/dist/src/msa/ClustalMSA.js.map +0 -1
- package/dist/src/msa/EmfMSA.d.ts +0 -27
- package/dist/src/msa/EmfMSA.js.map +0 -1
- package/dist/src/msa/FastaMSA.d.ts +0 -20
- package/dist/src/msa/FastaMSA.js +0 -75
- package/dist/src/msa/FastaMSA.js.map +0 -1
- package/dist/src/msa/StockholmMSA.d.ts +0 -54
- package/dist/src/msa/StockholmMSA.js +0 -113
- package/dist/src/msa/StockholmMSA.js.map +0 -1
- package/dist/src/msa/index.d.ts +0 -18
- package/dist/src/msa/index.js +0 -34
- package/dist/src/msa/index.js.map +0 -1
- package/dist/src/msa/index.test.d.ts +0 -1
- package/dist/src/msa/index.test.js +0 -96
- package/dist/src/msa/index.test.js.map +0 -1
- package/dist/src/msa/parseNewick.d.ts +0 -60
- package/dist/src/msa/parseNewick.js +0 -105
- package/dist/src/msa/parseNewick.js.map +0 -1
- package/dist/src/msa/stockholmParser.d.ts +0 -22
- package/dist/src/msa/stockholmParser.js +0 -141
- package/dist/src/msa/stockholmParser.js.map +0 -1
- package/dist/src/msa/stockholmParser.test.d.ts +0 -1
- package/dist/src/msa/stockholmParser.test.js +0 -111
- package/dist/src/msa/stockholmParser.test.js.map +0 -1
- package/dist/src/types.d.ts +0 -66
- package/dist/src/types.js +0 -2
- package/dist/src/types.js.map +0 -1
- package/dist/src/util.d.ts +0 -2
- package/dist/src/util.js +0 -10
- package/dist/src/util.js.map +0 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import BaseMSA from './BaseMSA.ts';
|
|
1
2
|
import type { NodeWithIds } from '../types.ts';
|
|
2
3
|
import type { StockholmData } from './stockholmParser.ts';
|
|
3
|
-
export default class StockholmMSA {
|
|
4
|
+
export default class StockholmMSA extends BaseMSA {
|
|
4
5
|
private data;
|
|
5
6
|
private MSA;
|
|
6
7
|
constructor(text: string, currentAlignment: number);
|
|
@@ -23,7 +24,6 @@ export default class StockholmMSA {
|
|
|
23
24
|
dbxref: string | undefined;
|
|
24
25
|
};
|
|
25
26
|
getNames(): string[];
|
|
26
|
-
getSeqCoords(): void;
|
|
27
27
|
getStructures(): Record<string, {
|
|
28
28
|
pdb: string;
|
|
29
29
|
chain: string;
|
package/dist/msa/StockholmMSA.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import parseNewick from "./parseNewick.js";
|
|
2
2
|
import { parseAll } from "./stockholmParser.js";
|
|
3
3
|
import { generateNodeIds } from "../util.js";
|
|
4
|
-
|
|
4
|
+
import BaseMSA from "./BaseMSA.js";
|
|
5
|
+
export default class StockholmMSA extends BaseMSA {
|
|
5
6
|
data;
|
|
6
7
|
MSA;
|
|
7
8
|
constructor(text, currentAlignment) {
|
|
9
|
+
super();
|
|
8
10
|
const res = parseAll(text);
|
|
9
11
|
this.data = res;
|
|
10
12
|
this.MSA = res[currentAlignment];
|
|
@@ -41,47 +43,29 @@ export default class StockholmMSA {
|
|
|
41
43
|
getNames() {
|
|
42
44
|
return Object.keys(this.MSA.seqdata);
|
|
43
45
|
}
|
|
44
|
-
getSeqCoords() { }
|
|
45
46
|
getStructures() {
|
|
46
47
|
const pdbRegex = /PDB; +(\S+) +(\S); ([0-9]+)-([0-9]+)/;
|
|
47
48
|
const drEntries = this.MSA.gs.DR ?? {};
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
const ret = {};
|
|
62
|
-
for (const entry of args) {
|
|
63
|
-
const { id, ...rest } = entry;
|
|
64
|
-
if (!ret[id]) {
|
|
65
|
-
ret[id] = [];
|
|
49
|
+
const result = {};
|
|
50
|
+
for (const [id, drList] of Object.entries(drEntries)) {
|
|
51
|
+
for (const dr of drList) {
|
|
52
|
+
const match = pdbRegex.exec(dr);
|
|
53
|
+
if (match) {
|
|
54
|
+
;
|
|
55
|
+
(result[id] ??= []).push({
|
|
56
|
+
pdb: match[1].toLowerCase(),
|
|
57
|
+
chain: match[2],
|
|
58
|
+
startPos: +match[3],
|
|
59
|
+
endPos: +match[4],
|
|
60
|
+
});
|
|
61
|
+
}
|
|
66
62
|
}
|
|
67
|
-
ret[id].push(rest);
|
|
68
63
|
}
|
|
69
|
-
return
|
|
64
|
+
return result;
|
|
70
65
|
}
|
|
71
66
|
getTree() {
|
|
72
67
|
const tree = this.MSA.gf.NH?.[0];
|
|
73
|
-
return tree
|
|
74
|
-
? generateNodeIds(parseNewick(tree))
|
|
75
|
-
: {
|
|
76
|
-
id: 'root',
|
|
77
|
-
name: 'root',
|
|
78
|
-
noTree: true,
|
|
79
|
-
children: this.getNames().map(name => ({
|
|
80
|
-
id: name,
|
|
81
|
-
children: [],
|
|
82
|
-
name,
|
|
83
|
-
})),
|
|
84
|
-
};
|
|
68
|
+
return tree ? generateNodeIds(parseNewick(tree)) : super.getTree();
|
|
85
69
|
}
|
|
86
70
|
get seqConsensus() {
|
|
87
71
|
return this.MSA.gc.seq_cons;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StockholmMSA.js","sourceRoot":"","sources":["../../src/msa/StockholmMSA.ts"],"names":[],"mappings":"AAAA,OAAO,WAAW,MAAM,kBAAkB,CAAA;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAA;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"StockholmMSA.js","sourceRoot":"","sources":["../../src/msa/StockholmMSA.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "msa-parsers",
|
|
3
|
-
"version": "5.0.
|
|
3
|
+
"version": "5.0.13",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/GMOD/JBrowseMSA.git",
|
|
9
|
+
"directory": "packages/msa-parsers"
|
|
10
|
+
},
|
|
6
11
|
"exports": {
|
|
7
12
|
".": {
|
|
8
13
|
"types": "./dist/index.d.ts",
|
|
@@ -23,7 +28,7 @@
|
|
|
23
28
|
},
|
|
24
29
|
"devDependencies": {
|
|
25
30
|
"typescript": "^6.0.2",
|
|
26
|
-
"vitest": "^4.1.
|
|
31
|
+
"vitest": "^4.1.4"
|
|
27
32
|
},
|
|
28
33
|
"scripts": {
|
|
29
34
|
"clean": "rimraf dist",
|
package/src/gff/gffToInterPro.ts
CHANGED
|
@@ -89,17 +89,6 @@ export function gffToInterProResults(
|
|
|
89
89
|
return results
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
-
/**
|
|
93
|
-
* Convert GFF string directly to InterProScan format
|
|
94
|
-
*/
|
|
95
|
-
export function parseGFFToInterPro(
|
|
96
|
-
gffStr: string,
|
|
97
|
-
parseGFFfn: (str: string) => GFFRecord[],
|
|
98
|
-
): Record<string, InterProScanResults> {
|
|
99
|
-
const records = parseGFFfn(gffStr)
|
|
100
|
-
return gffToInterProResults(records)
|
|
101
|
-
}
|
|
102
|
-
|
|
103
92
|
/**
|
|
104
93
|
* Create a full InterProScanResponse from GFF records
|
|
105
94
|
*/
|
package/src/msa/A3mMSA.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import BaseMSA from './BaseMSA.ts'
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* A3M Format Parser
|
|
@@ -22,7 +22,6 @@ import type { NodeWithIds } from '../types.ts'
|
|
|
22
22
|
* @see https://yanglab.qd.sdu.edu.cn/trRosetta/msa_format.html
|
|
23
23
|
*/
|
|
24
24
|
|
|
25
|
-
// Char code helpers for fast character classification
|
|
26
25
|
const CODE_A = 65 // 'A'
|
|
27
26
|
const CODE_Z = 90 // 'Z'
|
|
28
27
|
const CODE_a = 97 // 'a'
|
|
@@ -34,15 +33,15 @@ function isLower(code: number): boolean {
|
|
|
34
33
|
return code >= CODE_a && code <= CODE_z
|
|
35
34
|
}
|
|
36
35
|
|
|
37
|
-
export default class A3mMSA {
|
|
36
|
+
export default class A3mMSA extends BaseMSA {
|
|
38
37
|
private MSA: { seqdata: Record<string, string> }
|
|
39
38
|
private orderedNames: string[]
|
|
40
39
|
|
|
41
40
|
constructor(text: string) {
|
|
41
|
+
super()
|
|
42
42
|
const rawSeqs: string[] = []
|
|
43
43
|
const names: string[] = []
|
|
44
44
|
|
|
45
|
-
// First pass: parse sequences (like FASTA), preserving order
|
|
46
45
|
for (const entry of text.split('>')) {
|
|
47
46
|
if (!/\S/.test(entry)) {
|
|
48
47
|
continue
|
|
@@ -64,9 +63,6 @@ export default class A3mMSA {
|
|
|
64
63
|
this.MSA = { seqdata: this.expandA3M(rawSeqs, names) }
|
|
65
64
|
}
|
|
66
65
|
|
|
67
|
-
/**
|
|
68
|
-
* Detect if text is likely A3M format
|
|
69
|
-
*/
|
|
70
66
|
static sniff(text: string): boolean {
|
|
71
67
|
if (!text.startsWith('>')) {
|
|
72
68
|
return false
|
|
@@ -91,8 +87,6 @@ export default class A3mMSA {
|
|
|
91
87
|
return false
|
|
92
88
|
}
|
|
93
89
|
|
|
94
|
-
// Check for lowercase and compute match column lengths in single pass per sequence
|
|
95
|
-
// In A3M, match columns = uppercase letters + dashes (deletions)
|
|
96
90
|
let hasLowercase = false
|
|
97
91
|
let firstMatchLen = -1
|
|
98
92
|
let sameMatchLength = true
|
|
@@ -104,7 +98,6 @@ export default class A3mMSA {
|
|
|
104
98
|
if (isLower(code)) {
|
|
105
99
|
hasLowercase = true
|
|
106
100
|
} else if ((code >= CODE_A && code <= CODE_Z) || code === CODE_DASH) {
|
|
107
|
-
// Uppercase letters and dashes are match columns
|
|
108
101
|
matchLen++
|
|
109
102
|
}
|
|
110
103
|
}
|
|
@@ -121,14 +114,6 @@ export default class A3mMSA {
|
|
|
121
114
|
return hasLowercase && sameMatchLength
|
|
122
115
|
}
|
|
123
116
|
|
|
124
|
-
/**
|
|
125
|
-
* Expand A3M format to standard aligned format.
|
|
126
|
-
*
|
|
127
|
-
* In A3M, lowercase characters are insertions that implicitly introduce
|
|
128
|
-
* gaps in sequences that don't have an insert at that position.
|
|
129
|
-
* Gaps (-) following match columns in sequences without inserts align
|
|
130
|
-
* with lowercase inserts in other sequences.
|
|
131
|
-
*/
|
|
132
117
|
private expandA3M(
|
|
133
118
|
rawSeqs: string[],
|
|
134
119
|
names: string[],
|
|
@@ -138,8 +123,6 @@ export default class A3mMSA {
|
|
|
138
123
|
return {}
|
|
139
124
|
}
|
|
140
125
|
|
|
141
|
-
// Parse sequences: extract match chars (uppercase only) and insert content
|
|
142
|
-
// For each sequence, track: matchChars, insertContent (after each match)
|
|
143
126
|
const matchChars: string[][] = []
|
|
144
127
|
const insertContent: string[][] = []
|
|
145
128
|
|
|
@@ -153,10 +136,7 @@ export default class A3mMSA {
|
|
|
153
136
|
const code = seq.charCodeAt(i)
|
|
154
137
|
|
|
155
138
|
if ((code >= CODE_A && code <= CODE_Z) || code === CODE_DASH) {
|
|
156
|
-
// Uppercase letter or dash - match column (dash = deletion)
|
|
157
139
|
matches.push(seq[i]!)
|
|
158
|
-
// Collect following lowercase/dot characters as insert content
|
|
159
|
-
// Note: dash is NOT insert content, it's a match column
|
|
160
140
|
let ins = ''
|
|
161
141
|
let j = i + 1
|
|
162
142
|
while (j < seq.length) {
|
|
@@ -171,16 +151,13 @@ export default class A3mMSA {
|
|
|
171
151
|
inserts.push(ins)
|
|
172
152
|
i = j
|
|
173
153
|
} else if (code === CODE_DOT) {
|
|
174
|
-
// Leading dot (gap aligned to insert) - skip
|
|
175
154
|
i++
|
|
176
155
|
} else if (isLower(code)) {
|
|
177
|
-
// Leading insert before first match
|
|
178
156
|
let ins = ''
|
|
179
157
|
while (i < seq.length && isLower(seq.charCodeAt(i))) {
|
|
180
158
|
ins += seq[i]!
|
|
181
159
|
i++
|
|
182
160
|
}
|
|
183
|
-
// Add empty match with this insert
|
|
184
161
|
matches.push('')
|
|
185
162
|
inserts.push(ins)
|
|
186
163
|
} else {
|
|
@@ -192,15 +169,12 @@ export default class A3mMSA {
|
|
|
192
169
|
insertContent.push(inserts)
|
|
193
170
|
}
|
|
194
171
|
|
|
195
|
-
// Find number of match positions (should be same for all valid A3M)
|
|
196
172
|
const numPositions = Math.max(...matchChars.map(m => m.length), 0)
|
|
197
173
|
|
|
198
|
-
// Find max insert length at each position (only count lowercase, not gaps)
|
|
199
174
|
const maxInserts = new Array<number>(numPositions).fill(0)
|
|
200
175
|
for (let seqIdx = 0; seqIdx < numSeqs; seqIdx++) {
|
|
201
176
|
const inserts = insertContent[seqIdx]!
|
|
202
177
|
for (let pos = 0; pos < inserts.length; pos++) {
|
|
203
|
-
// Count only lowercase characters as actual inserts
|
|
204
178
|
let lcCount = 0
|
|
205
179
|
for (const c of inserts[pos]!) {
|
|
206
180
|
if (isLower(c.charCodeAt(0))) {
|
|
@@ -213,7 +187,6 @@ export default class A3mMSA {
|
|
|
213
187
|
}
|
|
214
188
|
}
|
|
215
189
|
|
|
216
|
-
// Build expanded sequences
|
|
217
190
|
const expanded: Record<string, string> = {}
|
|
218
191
|
|
|
219
192
|
for (let seqIdx = 0; seqIdx < numSeqs; seqIdx++) {
|
|
@@ -228,10 +201,8 @@ export default class A3mMSA {
|
|
|
228
201
|
const matchChar = matches[pos]!
|
|
229
202
|
const insContent = inserts[pos] || ''
|
|
230
203
|
|
|
231
|
-
// Add match character (or gap if empty)
|
|
232
204
|
result.push(matchChar || '-')
|
|
233
205
|
|
|
234
|
-
// Process insert content
|
|
235
206
|
let lcContent = ''
|
|
236
207
|
for (const c of insContent) {
|
|
237
208
|
if (isLower(c.charCodeAt(0))) {
|
|
@@ -239,16 +210,13 @@ export default class A3mMSA {
|
|
|
239
210
|
}
|
|
240
211
|
}
|
|
241
212
|
|
|
242
|
-
// Add the insert content (uppercased)
|
|
243
213
|
result.push(lcContent)
|
|
244
214
|
|
|
245
|
-
// Pad with gaps to match max insert length
|
|
246
215
|
const padding = maxIns - lcContent.length
|
|
247
216
|
if (padding > 0) {
|
|
248
217
|
result.push('.'.repeat(padding))
|
|
249
218
|
}
|
|
250
219
|
} else {
|
|
251
|
-
// This sequence is shorter - add gaps
|
|
252
220
|
result.push('-')
|
|
253
221
|
if (maxIns > 0) {
|
|
254
222
|
result.push('.'.repeat(maxIns))
|
|
@@ -266,10 +234,6 @@ export default class A3mMSA {
|
|
|
266
234
|
return this.MSA
|
|
267
235
|
}
|
|
268
236
|
|
|
269
|
-
getRowData() {
|
|
270
|
-
return undefined
|
|
271
|
-
}
|
|
272
|
-
|
|
273
237
|
getNames() {
|
|
274
238
|
return this.orderedNames
|
|
275
239
|
}
|
|
@@ -282,41 +246,4 @@ export default class A3mMSA {
|
|
|
282
246
|
const name = Object.keys(this.MSA.seqdata)[0]
|
|
283
247
|
return name ? this.getRow(name).length : 0
|
|
284
248
|
}
|
|
285
|
-
|
|
286
|
-
getStructures() {
|
|
287
|
-
return {}
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
get alignmentNames() {
|
|
291
|
-
return []
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
getHeader() {
|
|
295
|
-
return {}
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
getTree(): NodeWithIds {
|
|
299
|
-
return {
|
|
300
|
-
id: 'root',
|
|
301
|
-
name: 'root',
|
|
302
|
-
noTree: true,
|
|
303
|
-
children: this.getNames().map(name => ({
|
|
304
|
-
id: name,
|
|
305
|
-
children: [],
|
|
306
|
-
name,
|
|
307
|
-
})),
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
get seqConsensus() {
|
|
312
|
-
return undefined
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
get secondaryStructureConsensus() {
|
|
316
|
-
return undefined
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
get tracks() {
|
|
320
|
-
return []
|
|
321
|
-
}
|
|
322
249
|
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { NodeWithIds } from '../types.ts'
|
|
2
|
+
|
|
3
|
+
export default abstract class BaseMSA {
|
|
4
|
+
abstract getMSA(): unknown
|
|
5
|
+
abstract getRow(name: string): string
|
|
6
|
+
abstract getWidth(): number
|
|
7
|
+
abstract getNames(): string[]
|
|
8
|
+
|
|
9
|
+
getTree(): NodeWithIds {
|
|
10
|
+
return {
|
|
11
|
+
id: 'root',
|
|
12
|
+
name: 'root',
|
|
13
|
+
noTree: true,
|
|
14
|
+
children: this.getNames().map(name => ({
|
|
15
|
+
id: name,
|
|
16
|
+
children: [],
|
|
17
|
+
name,
|
|
18
|
+
})),
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
getRowData(_name: string) {
|
|
23
|
+
return undefined as { name?: string; accession?: string; dbxref?: string } | undefined
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
getStructures(): Record<string, unknown> {
|
|
27
|
+
return {}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
getHeader(): unknown {
|
|
31
|
+
return {}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
get alignmentNames(): string[] {
|
|
35
|
+
return []
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
get seqConsensus(): string | undefined {
|
|
39
|
+
return undefined
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
get secondaryStructureConsensus(): string | undefined {
|
|
43
|
+
return undefined
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
get tracks(): unknown[] {
|
|
47
|
+
return []
|
|
48
|
+
}
|
|
49
|
+
}
|
package/src/msa/ClustalMSA.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { parse } from 'clustal-js'
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
import BaseMSA from './BaseMSA.ts'
|
|
4
4
|
|
|
5
|
-
export default class ClustalMSA {
|
|
5
|
+
export default class ClustalMSA extends BaseMSA {
|
|
6
6
|
private MSA: ReturnType<typeof parse>
|
|
7
7
|
|
|
8
8
|
constructor(text: string) {
|
|
9
|
+
super()
|
|
9
10
|
this.MSA = parse(text)
|
|
10
11
|
}
|
|
11
12
|
|
|
@@ -21,10 +22,6 @@ export default class ClustalMSA {
|
|
|
21
22
|
return this.MSA.alns[0]!.seq.length
|
|
22
23
|
}
|
|
23
24
|
|
|
24
|
-
getRowData() {
|
|
25
|
-
return undefined
|
|
26
|
-
}
|
|
27
|
-
|
|
28
25
|
getHeader() {
|
|
29
26
|
return this.MSA.header
|
|
30
27
|
}
|
|
@@ -33,35 +30,7 @@ export default class ClustalMSA {
|
|
|
33
30
|
return this.MSA.alns.map(aln => aln.id)
|
|
34
31
|
}
|
|
35
32
|
|
|
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
33
|
get seqConsensus() {
|
|
58
34
|
return this.MSA.consensus
|
|
59
35
|
}
|
|
60
|
-
get secondaryStructureConsensus() {
|
|
61
|
-
return undefined
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
get tracks() {
|
|
65
|
-
return []
|
|
66
|
-
}
|
|
67
36
|
}
|
package/src/msa/EmfMSA.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { parseEmfAln } from 'emf-js'
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
import BaseMSA from './BaseMSA.ts'
|
|
4
4
|
|
|
5
|
-
export default class EmfMSA {
|
|
5
|
+
export default class EmfMSA extends BaseMSA {
|
|
6
6
|
private MSA: ReturnType<typeof parseEmfAln>
|
|
7
7
|
|
|
8
8
|
constructor(text: string) {
|
|
9
|
+
super()
|
|
9
10
|
this.MSA = parseEmfAln(text)
|
|
10
11
|
}
|
|
11
12
|
|
|
@@ -21,10 +22,6 @@ export default class EmfMSA {
|
|
|
21
22
|
return this.MSA[0]!.seq.length
|
|
22
23
|
}
|
|
23
24
|
|
|
24
|
-
getRowData() {
|
|
25
|
-
return undefined
|
|
26
|
-
}
|
|
27
|
-
|
|
28
25
|
getHeader() {
|
|
29
26
|
return ''
|
|
30
27
|
}
|
|
@@ -32,36 +29,4 @@ export default class EmfMSA {
|
|
|
32
29
|
getNames() {
|
|
33
30
|
return this.MSA.map(aln => aln.protein)
|
|
34
31
|
}
|
|
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
32
|
}
|
package/src/msa/FastaMSA.ts
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import
|
|
1
|
+
import BaseMSA from './BaseMSA.ts'
|
|
2
2
|
|
|
3
|
-
export default class FastaMSA {
|
|
3
|
+
export default class FastaMSA extends BaseMSA {
|
|
4
4
|
private MSA: {
|
|
5
5
|
seqdata: Record<string, string>
|
|
6
6
|
colonNormalized: Record<string, string>
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
constructor(text: string) {
|
|
10
|
+
super()
|
|
10
11
|
const seqdata: Record<string, string> = {}
|
|
11
12
|
const colonNormalized: Record<string, string> = {}
|
|
12
13
|
for (const entry of text.split('>')) {
|
|
@@ -34,10 +35,6 @@ export default class FastaMSA {
|
|
|
34
35
|
return this.MSA
|
|
35
36
|
}
|
|
36
37
|
|
|
37
|
-
getRowData() {
|
|
38
|
-
return undefined
|
|
39
|
-
}
|
|
40
|
-
|
|
41
38
|
getNames() {
|
|
42
39
|
return Object.keys(this.MSA.seqdata)
|
|
43
40
|
}
|
|
@@ -54,40 +51,4 @@ export default class FastaMSA {
|
|
|
54
51
|
const name = Object.keys(this.MSA.seqdata)[0]!
|
|
55
52
|
return this.getRow(name).length
|
|
56
53
|
}
|
|
57
|
-
|
|
58
|
-
getStructures() {
|
|
59
|
-
return {}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
get alignmentNames() {
|
|
63
|
-
return []
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
getHeader() {
|
|
67
|
-
return {}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
getTree(): NodeWithIds {
|
|
71
|
-
return {
|
|
72
|
-
id: 'root',
|
|
73
|
-
name: 'root',
|
|
74
|
-
noTree: true,
|
|
75
|
-
children: this.getNames().map(name => ({
|
|
76
|
-
id: name,
|
|
77
|
-
children: [],
|
|
78
|
-
name,
|
|
79
|
-
})),
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
get seqConsensus() {
|
|
84
|
-
return undefined
|
|
85
|
-
}
|
|
86
|
-
get secondaryStructureConsensus() {
|
|
87
|
-
return undefined
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
get tracks() {
|
|
91
|
-
return []
|
|
92
|
-
}
|
|
93
54
|
}
|
package/src/msa/StockholmMSA.ts
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import parseNewick from './parseNewick.ts'
|
|
2
2
|
import { parseAll } from './stockholmParser.ts'
|
|
3
3
|
import { generateNodeIds } from '../util.ts'
|
|
4
|
+
import BaseMSA from './BaseMSA.ts'
|
|
4
5
|
|
|
5
6
|
import type { NodeWithIds } from '../types.ts'
|
|
6
7
|
import type { StockholmData } from './stockholmParser.ts'
|
|
7
8
|
|
|
8
|
-
export default class StockholmMSA {
|
|
9
|
+
export default class StockholmMSA extends BaseMSA {
|
|
9
10
|
private data: StockholmData[]
|
|
10
11
|
private MSA: StockholmData
|
|
11
12
|
|
|
12
13
|
constructor(text: string, currentAlignment: number) {
|
|
14
|
+
super()
|
|
13
15
|
const res = parseAll(text)
|
|
14
16
|
this.data = res
|
|
15
17
|
this.MSA = res[currentAlignment]!
|
|
@@ -58,55 +60,32 @@ export default class StockholmMSA {
|
|
|
58
60
|
return Object.keys(this.MSA.seqdata)
|
|
59
61
|
}
|
|
60
62
|
|
|
61
|
-
getSeqCoords() {}
|
|
62
|
-
|
|
63
63
|
getStructures() {
|
|
64
64
|
const pdbRegex = /PDB; +(\S+) +(\S); ([0-9]+)-([0-9]+)/
|
|
65
65
|
const drEntries = this.MSA.gs.DR ?? {}
|
|
66
|
-
const
|
|
67
|
-
.flatMap(([id, drList]) =>
|
|
68
|
-
drList.map(dr => {
|
|
69
|
-
const match = pdbRegex.exec(dr)
|
|
70
|
-
return match ? { id, match } : null
|
|
71
|
-
}),
|
|
72
|
-
)
|
|
73
|
-
.filter((item): item is { id: string; match: RegExpExecArray } => !!item)
|
|
74
|
-
.map(({ id, match }) => ({
|
|
75
|
-
id,
|
|
76
|
-
pdb: match[1]!.toLowerCase(),
|
|
77
|
-
chain: match[2]!,
|
|
78
|
-
startPos: +match[3]!,
|
|
79
|
-
endPos: +match[4]!,
|
|
80
|
-
}))
|
|
81
|
-
|
|
82
|
-
const ret = {} as Record<
|
|
66
|
+
const result: Record<
|
|
83
67
|
string,
|
|
84
68
|
{ pdb: string; chain: string; startPos: number; endPos: number }[]
|
|
85
|
-
>
|
|
86
|
-
for (const
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
|
|
69
|
+
> = {}
|
|
70
|
+
for (const [id, drList] of Object.entries(drEntries)) {
|
|
71
|
+
for (const dr of drList) {
|
|
72
|
+
const match = pdbRegex.exec(dr)
|
|
73
|
+
if (match) {
|
|
74
|
+
;(result[id] ??= []).push({
|
|
75
|
+
pdb: match[1]!.toLowerCase(),
|
|
76
|
+
chain: match[2]!,
|
|
77
|
+
startPos: +match[3]!,
|
|
78
|
+
endPos: +match[4]!,
|
|
79
|
+
})
|
|
80
|
+
}
|
|
90
81
|
}
|
|
91
|
-
ret[id].push(rest)
|
|
92
82
|
}
|
|
93
|
-
return
|
|
83
|
+
return result
|
|
94
84
|
}
|
|
95
85
|
|
|
96
86
|
getTree(): NodeWithIds {
|
|
97
87
|
const tree = this.MSA.gf.NH?.[0]
|
|
98
|
-
return tree
|
|
99
|
-
? generateNodeIds(parseNewick(tree))
|
|
100
|
-
: {
|
|
101
|
-
id: 'root',
|
|
102
|
-
name: 'root',
|
|
103
|
-
noTree: true,
|
|
104
|
-
children: this.getNames().map(name => ({
|
|
105
|
-
id: name,
|
|
106
|
-
children: [],
|
|
107
|
-
name,
|
|
108
|
-
})),
|
|
109
|
-
}
|
|
88
|
+
return tree ? generateNodeIds(parseNewick(tree)) : super.getTree()
|
|
110
89
|
}
|
|
111
90
|
|
|
112
91
|
get seqConsensus() {
|