clustal-js 1.0.4 → 2.0.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/CHANGELOG.md CHANGED
@@ -1,8 +1,19 @@
1
+ # v2.0.1
2
+
3
+ - Fix preversion build script
4
+
5
+ # v2.0.0
6
+
7
+ - Parse pairwise format, outputted by e.g. EMBOSS needle, etc
8
+
9
+ # v1.0.4
10
+
11
+ - Fix package name in README
12
+
1
13
  # v1.0.3
2
14
 
3
15
  - Add generated typescript declarations to output
4
16
 
5
-
6
17
  ## v1.0.2
7
18
 
8
19
  - Add dist folder to package.json
package/README.md CHANGED
@@ -4,11 +4,10 @@
4
4
 
5
5
  This parses clustal output format
6
6
 
7
-
8
7
  ## Usage
9
8
 
10
- ```js
11
- import {parse} from 'clustal-js'
9
+ ```typescript
10
+ import { parse } from 'clustal-js'
12
11
  const file = fs.readFileSync('test.aln', 'utf8')
13
12
  const ret = parse(file)
14
13
  ```
@@ -57,6 +56,103 @@ Output
57
56
  version: '1.2.4' } }
58
57
  ```
59
58
 
59
+ ### Parse pairwise outputs
60
+
61
+ ```typescript
62
+ import { parsePairwise } from 'clustal-js'
63
+ const file = fs.readFileSync('test.aln', 'utf8')
64
+ const ret = parse(file)
65
+ ```
66
+
67
+ Input test.aln (e.g. from EMBOSS needle)
68
+
69
+ ```
70
+ ########################################
71
+ # Program: needle
72
+ # Rundate: Mon 5 Feb 2024 17:52:19
73
+ # Commandline: needle
74
+ # -auto
75
+ # -stdout
76
+ # -asequence emboss_needle-R20240205-175207-0261-70863964-p1m.asequence
77
+ # -bsequence emboss_needle-R20240205-175207-0261-70863964-p1m.bsequence
78
+ # Align_format: srspair
79
+ # Report_file: stdout
80
+ ########################################
81
+
82
+ #=======================================
83
+ #
84
+ # Aligned_sequences: 2
85
+ # 1: a
86
+ # 2: b
87
+ # Matrix: EBLOSUM62
88
+ # Gap_penalty: 10.0
89
+ # Extend_penalty: 0.5
90
+ #
91
+ # Length: 614
92
+ # Identity: 221/614 (36.0%)
93
+ # Similarity: 221/614 (36.0%)
94
+ # Gaps: 393/614 (64.0%)
95
+ # Score: 1114.0
96
+ #
97
+ #
98
+ #=======================================
99
+
100
+ a 1 MGQKGHKDSLYPCGGTPESSLHEALDQCMTALDLFLTNQFSEALSYLKPR 50
101
+
102
+ b 0 -------------------------------------------------- 0
103
+
104
+ a 51 TKESMYHSLTYATILEMQAMMTFDPQDILLAGNMMKEAQMLCQRHRRKSS 100
105
+
106
+ b 0 -------------------------------------------------- 0
107
+
108
+ a 101 VTDSFSSLVNRPTLGQFTEEEIHAEVCYAECLLQRAALTFLQGSSHGGAV 150
109
+
110
+ b 0 -------------------------------------------------- 0
111
+
112
+ a 151 RPRALHDPSHACSCPPGPGRQHLFLLQDENMVSFIKGGIKVRNSYQTYKE 200
113
+
114
+ b 0 -------------------------------------------------- 0
115
+
116
+ a 201 LDSLVQSSQYCKGENHPHFEGGVKLGVGAFNLTLSMLPTRILRLLEFVGF 250
117
+
118
+ b 0 -------------------------------------------------- 0
119
+
120
+ a 251 SGNKDYGLLQLEEGASGHSFRSVLCVMLLLCYHTFLTFVLGTGNVNIEEA 300
121
+
122
+ b 0 -------------------------------------------------- 0
123
+
124
+ a 301 EKLLKPYLNRYPKGAIFLFFAGRIEVIKGNIDAAIRRFEECCEAQQHWKQ 350
125
+
126
+ b 0 -------------------------------------------------- 0
127
+
128
+ a 351 FHHMCYWELMWCFTYKGQWKMSYFYADLLSKENCWSKATYIYMKAAYLSM 400
129
+ ||||||||
130
+ b 1 ------------------------------------------MKAAYLSM 8
131
+
132
+ a 401 FGKEDHKPFGDDEVELFRAVPGLKLKIAGKSLPTEKFAIRKSRRYFSSNP 450
133
+ ||||||||||||||||||||||||||||||||||||||||||||||||||
134
+ b 9 FGKEDHKPFGDDEVELFRAVPGLKLKIAGKSLPTEKFAIRKSRRYFSSNP 58
135
+
136
+ a 451 ISLPVPALEMMYIWNGYAVIGKQPKLTDGILEIITKAEEMLEKGPENEYS 500
137
+ ||||||||||||||||||||||||||||||||||||||||||||||||||
138
+ b 59 ISLPVPALEMMYIWNGYAVIGKQPKLTDGILEIITKAEEMLEKGPENEYS 108
139
+
140
+ a 501 VDDECLVKLLKGLCLKYLGRVQEAEENFRSISANEKKIKYDHYLIPNALL 550
141
+ ||||||||||||||||||||||||||||||||||||||||||||||||||
142
+ b 109 VDDECLVKLLKGLCLKYLGRVQEAEENFRSISANEKKIKYDHYLIPNALL 158
143
+
144
+ a 551 ELALLLMEQDRNEEAIKLLESAKQNYKNYSMESRTHFRIQAATLQAKSSL 600
145
+ ||||||||||||||||||||||||||||||||||||||||||||||||||
146
+ b 159 ELALLLMEQDRNEEAIKLLESAKQNYKNYSMESRTHFRIQAATLQAKSSL 208
147
+
148
+ a 601 ENSSRSMVSSVSL- 613
149
+ |||||||||||||
150
+ b 209 ENSSRSMVSSVSL* 222
151
+
152
+
153
+ #---------------------------------------
154
+ #---------------------------------------
155
+ ```
60
156
 
61
157
  ### Notes
62
158
 
@@ -0,0 +1,36 @@
1
+ export declare function parseClustalIter(arr: Iterator<string>): {
2
+ consensus: string;
3
+ alns: {
4
+ id: any;
5
+ seq: any;
6
+ }[];
7
+ header: {
8
+ info: string;
9
+ version: string;
10
+ };
11
+ };
12
+ export declare function parsePairwiseIter(arr: string): {
13
+ consensus: string;
14
+ alns: {
15
+ id: any;
16
+ seq: any;
17
+ }[];
18
+ };
19
+ export declare function parse(contents: string): {
20
+ consensus: string;
21
+ alns: {
22
+ id: any;
23
+ seq: any;
24
+ }[];
25
+ header: {
26
+ info: string;
27
+ version: string;
28
+ };
29
+ };
30
+ export declare function parsePairwise(contents: string): {
31
+ consensus: string;
32
+ alns: {
33
+ id: any;
34
+ seq: any;
35
+ }[];
36
+ };
package/dist/index.js ADDED
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parsePairwise = exports.parse = exports.parsePairwiseIter = exports.parseClustalIter = void 0;
4
+ const pairwise_1 = require("./pairwise");
5
+ const util_1 = require("./util");
6
+ function parseClustalIter(arr) {
7
+ const line = (0, util_1.getFirstNonEmptyLine)(arr);
8
+ if (!line) {
9
+ throw new Error('Empty file received');
10
+ }
11
+ const header = (0, util_1.parseHeader)(line);
12
+ const res = (0, util_1.parseBlocks)(arr);
13
+ if (res === undefined) {
14
+ throw new Error('No blocks parsed');
15
+ }
16
+ const alns = res.seqs.map((n, index) => ({ id: res.ids[index], seq: n }));
17
+ const { consensus } = res;
18
+ if (consensus.length != alns[0].seq.length) {
19
+ throw new Error(`Consensus length != sequence length. Con ${consensus.length} seq ${alns[0].seq.length}`);
20
+ }
21
+ return { consensus, alns, header };
22
+ }
23
+ exports.parseClustalIter = parseClustalIter;
24
+ function parsePairwiseIter(arr) {
25
+ const res = (0, pairwise_1.parsePairwiseBlocks)(arr.split('\n')[Symbol.iterator]());
26
+ if (res === undefined) {
27
+ throw new Error('No blocks parsed');
28
+ }
29
+ const alns = res.seqs.map((n, index) => ({ id: res.ids[index], seq: n }));
30
+ const { consensus } = res;
31
+ if (consensus.length != alns[0].seq.length) {
32
+ throw new Error(`Consensus length != sequence length. Con ${consensus.length} seq ${alns[0].seq.length}`);
33
+ }
34
+ return { consensus, alns };
35
+ }
36
+ exports.parsePairwiseIter = parsePairwiseIter;
37
+ function parse(contents) {
38
+ const iter = contents.split('\n')[Symbol.iterator]();
39
+ return parseClustalIter(iter);
40
+ }
41
+ exports.parse = parse;
42
+ function parsePairwise(contents) {
43
+ const res = contents
44
+ .split('\n')
45
+ .filter(f => !f.startsWith('#'))
46
+ .join('\n');
47
+ return parsePairwiseIter(res);
48
+ }
49
+ exports.parsePairwise = parsePairwise;
@@ -0,0 +1,11 @@
1
+ export declare function getSeqBounds(line: string): readonly [number, number];
2
+ export declare function parsePairwiseBlock(arr: Iterator<string>): {
3
+ ids: any[];
4
+ seqs: any[];
5
+ consensus: string;
6
+ } | undefined;
7
+ export declare function parsePairwiseBlocks(arr: Iterator<string>): {
8
+ ids: any[];
9
+ seqs: any[];
10
+ consensus: string;
11
+ } | undefined;
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parsePairwiseBlocks = exports.parsePairwiseBlock = exports.getSeqBounds = void 0;
4
+ const util_1 = require("./util");
5
+ function getSeqBounds(line) {
6
+ const fields = line.split(/\s+/);
7
+ const k1 = fields[0].length + fields[1].length;
8
+ const temp = line.slice(k1);
9
+ const s = k1 + temp.indexOf(fields[2]);
10
+ const e = s + fields[2].length;
11
+ return [s, e];
12
+ }
13
+ exports.getSeqBounds = getSeqBounds;
14
+ // Use the first block to get the sequence identifiers
15
+ function parsePairwiseBlock(arr) {
16
+ let line = (0, util_1.getFirstNonEmptyLine)(arr);
17
+ const block = [];
18
+ let consensusLine = '';
19
+ if (!line) {
20
+ return undefined;
21
+ }
22
+ while (line) {
23
+ if (line[0] !== ' ') {
24
+ block.push(line);
25
+ }
26
+ else {
27
+ consensusLine = line;
28
+ }
29
+ line = arr.next().value;
30
+ }
31
+ const [start, end] = getSeqBounds(block[0]);
32
+ const fields = block.map(s => s.split(/\s+/));
33
+ const ids = fields.map(s => s[0]);
34
+ const seqs = fields.map(s => s[2]);
35
+ let consensus = consensusLine.slice(start, end);
36
+ // handle if the consensus trailing whitespace got trimmed
37
+ const remainder = seqs[0].length - consensus.length;
38
+ if (remainder) {
39
+ consensus += ' '.repeat(remainder);
40
+ }
41
+ return { ids, seqs, consensus };
42
+ }
43
+ exports.parsePairwiseBlock = parsePairwiseBlock;
44
+ function parsePairwiseBlocks(arr) {
45
+ let block;
46
+ const res = parsePairwiseBlock(arr);
47
+ if (res !== undefined) {
48
+ while ((block = parsePairwiseBlock(arr))) {
49
+ for (let i = 0; i < block.seqs.length; i++) {
50
+ res.seqs[i] += block.seqs[i];
51
+ }
52
+ res.consensus += block.consensus;
53
+ }
54
+ }
55
+ return res;
56
+ }
57
+ exports.parsePairwiseBlocks = parsePairwiseBlocks;
package/dist/util.d.ts ADDED
@@ -0,0 +1,17 @@
1
+ export declare function parseVersion(line: string): string;
2
+ export declare function parseHeader(info: string): {
3
+ info: string;
4
+ version: string;
5
+ };
6
+ export declare function getFirstNonEmptyLine(arr: Iterator<string>): any;
7
+ export declare function getSeqBounds(line: string): readonly [number, number];
8
+ export declare function parseBlock(arr: Iterator<string>): {
9
+ ids: any[];
10
+ seqs: any[];
11
+ consensus: string;
12
+ } | undefined;
13
+ export declare function parseBlocks(arr: Iterator<string>): {
14
+ ids: any[];
15
+ seqs: any[];
16
+ consensus: string;
17
+ } | undefined;
package/dist/util.js ADDED
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseBlocks = exports.parseBlock = exports.getSeqBounds = exports.getFirstNonEmptyLine = exports.parseHeader = exports.parseVersion = void 0;
4
+ function parseVersion(line) {
5
+ const res = line.match(/\(?(\d+(\.\d+)+)\)?/);
6
+ return res && res.length > 1 ? res[1] : '';
7
+ }
8
+ exports.parseVersion = parseVersion;
9
+ function parseHeader(info) {
10
+ const knownHeaders = ['CLUSTAL', 'PROBCONS', 'MUSCLE', 'MSAPROBS', 'Kalign'];
11
+ if (!knownHeaders.some(l => info.startsWith(l))) {
12
+ console.warn(`${info} is not a known CLUSTAL header: ${knownHeaders.join(',')}, proceeding but could indicate an issue`);
13
+ }
14
+ const version = parseVersion(info);
15
+ return { info, version };
16
+ }
17
+ exports.parseHeader = parseHeader;
18
+ function getFirstNonEmptyLine(arr) {
19
+ // There should be two blank lines after the header line
20
+ let line = arr.next();
21
+ while (!line.done && line.value.trim() === '') {
22
+ line = arr.next();
23
+ }
24
+ return line.value;
25
+ }
26
+ exports.getFirstNonEmptyLine = getFirstNonEmptyLine;
27
+ function getSeqBounds(line) {
28
+ const fields = line.split(/\s+/);
29
+ const temp = line.slice(fields[0].length);
30
+ const s = fields[0].length + temp.indexOf(fields[1]);
31
+ const e = s + fields[1].length;
32
+ return [s, e];
33
+ }
34
+ exports.getSeqBounds = getSeqBounds;
35
+ // Use the first block to get the sequence identifiers
36
+ function parseBlock(arr) {
37
+ let line = getFirstNonEmptyLine(arr);
38
+ const block = [];
39
+ let consensusLine = '';
40
+ if (!line) {
41
+ return undefined;
42
+ }
43
+ while (line) {
44
+ if (line[0] !== ' ') {
45
+ block.push(line);
46
+ }
47
+ else {
48
+ consensusLine = line;
49
+ }
50
+ line = arr.next().value;
51
+ }
52
+ const [start, end] = getSeqBounds(block[0]);
53
+ const fields = block.map(s => s.split(/\s+/));
54
+ const ids = fields.map(s => s[0]);
55
+ const seqs = block.map(s => s.slice(start, end));
56
+ let consensus = consensusLine.slice(start, end);
57
+ // handle if the consensus trailing whitespace got trimmed
58
+ const remainder = seqs[0].length - consensus.length;
59
+ if (remainder) {
60
+ consensus += ' '.repeat(remainder);
61
+ }
62
+ return { ids, seqs, consensus };
63
+ }
64
+ exports.parseBlock = parseBlock;
65
+ function parseBlocks(arr) {
66
+ let block;
67
+ const res = parseBlock(arr);
68
+ if (res !== undefined) {
69
+ while ((block = parseBlock(arr))) {
70
+ for (let i = 0; i < block.seqs.length; i++) {
71
+ res.seqs[i] += block.seqs[i];
72
+ }
73
+ res.consensus += block.consensus;
74
+ }
75
+ }
76
+ return res;
77
+ }
78
+ exports.parseBlocks = parseBlocks;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clustal-js",
3
- "version": "1.0.4",
3
+ "version": "2.0.1",
4
4
  "main": "dist/index.js",
5
5
  "repository": "cmdcolin/clustal-js",
6
6
  "files": [
@@ -8,33 +8,26 @@
8
8
  ],
9
9
  "license": "MIT",
10
10
  "devDependencies": {
11
- "@babel/cli": "^7.12.10",
12
- "@babel/core": "^7.12.10",
13
- "@babel/plugin-proposal-class-properties": "^7.12.1",
14
- "@babel/plugin-transform-runtime": "^7.12.10",
15
- "@babel/preset-env": "^7.12.11",
16
- "@babel/preset-typescript": "^7.12.7",
17
- "@types/jest": "^26.0.20",
18
- "@types/node": "^14.14.22",
19
- "@typescript-eslint/eslint-plugin": "^4.14.2",
20
- "@typescript-eslint/parser": "^4.14.2",
21
- "babel-eslint": "^10.0.1",
22
- "babel-jest": "^26.6.3",
23
- "eslint": "^7.19.0",
24
- "eslint-config-airbnb-base": "^14.2.1",
25
- "eslint-config-prettier": "^7.2.0",
26
- "eslint-plugin-import": "^2.22.1",
27
- "eslint-plugin-prettier": "^3.3.1",
28
- "jest": "^26.6.3",
29
- "jest-cli": "^26.6.3",
30
- "prettier": "^2.2.1",
31
- "ts-jest": "^26.5.0",
32
- "typescript": "^4.1.3"
11
+ "@types/jest": "^29.5.12",
12
+ "@types/node": "^20.11.16",
13
+ "@typescript-eslint/eslint-plugin": "^6.21.0",
14
+ "@typescript-eslint/parser": "^6.21.0",
15
+ "eslint": "^8.56.0",
16
+ "eslint-config-prettier": "^9.1.0",
17
+ "eslint-plugin-prettier": "^5.1.3",
18
+ "eslint-plugin-unicorn": "^50.0.1",
19
+ "jest": "^29.7.0",
20
+ "prettier": "^3.2.5",
21
+ "ts-jest": "^29.1.2",
22
+ "typescript": "^5.3.3"
33
23
  },
34
24
  "scripts": {
25
+ "clean": "rimraf dist",
35
26
  "test": "jest",
36
27
  "lint": "eslint --ext .ts src test",
37
28
  "build": "tsc",
29
+ "prebuild": "npm run clean",
30
+ "preversion": "npm run lint && npm test && npm run build",
38
31
  "postversion": "git push --follow-tags"
39
32
  }
40
33
  }