p2s_mapper 1.0.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/LICENSE +21 -0
- package/README.md +148 -0
- package/dist/alignmentQuality.d.ts +58 -0
- package/dist/alignmentQuality.js +108 -0
- package/dist/alignmentQuality.js.map +1 -0
- package/dist/alphaFoldModels.d.ts +29 -0
- package/dist/alphaFoldModels.js +60 -0
- package/dist/alphaFoldModels.js.map +1 -0
- package/dist/caCoordsToPdb.d.ts +18 -0
- package/dist/caCoordsToPdb.js +95 -0
- package/dist/caCoordsToPdb.js.map +1 -0
- package/dist/chooseMappedEntity.d.ts +55 -0
- package/dist/chooseMappedEntity.js +140 -0
- package/dist/chooseMappedEntity.js.map +1 -0
- package/dist/coordinates.d.ts +66 -0
- package/dist/coordinates.js +66 -0
- package/dist/coordinates.js.map +1 -0
- package/dist/dbIds.d.ts +16 -0
- package/dist/dbIds.js +42 -0
- package/dist/dbIds.js.map +1 -0
- package/dist/extractPerResidueConfidence.d.ts +49 -0
- package/dist/extractPerResidueConfidence.js +42 -0
- package/dist/extractPerResidueConfidence.js.map +1 -0
- package/dist/extractStructureSequences.d.ts +142 -0
- package/dist/extractStructureSequences.js +217 -0
- package/dist/extractStructureSequences.js.map +1 -0
- package/dist/fetchUtils.d.ts +34 -0
- package/dist/fetchUtils.js +91 -0
- package/dist/fetchUtils.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.js +46 -0
- package/dist/index.js.map +1 -0
- package/dist/invertMap.d.ts +2 -0
- package/dist/invertMap.js +8 -0
- package/dist/invertMap.js.map +1 -0
- package/dist/isoformRanking.d.ts +47 -0
- package/dist/isoformRanking.js +91 -0
- package/dist/isoformRanking.js.map +1 -0
- package/dist/mappings.d.ts +58 -0
- package/dist/mappings.js +193 -0
- package/dist/mappings.js.map +1 -0
- package/dist/package.json +1 -0
- package/dist/pairwiseAlignment.d.ts +35 -0
- package/dist/pairwiseAlignment.js +337 -0
- package/dist/pairwiseAlignment.js.map +1 -0
- package/dist/pdbUniProtMapping.d.ts +75 -0
- package/dist/pdbUniProtMapping.js +241 -0
- package/dist/pdbUniProtMapping.js.map +1 -0
- package/dist/pdbeBestStructures.d.ts +23 -0
- package/dist/pdbeBestStructures.js +79 -0
- package/dist/pdbeBestStructures.js.map +1 -0
- package/dist/pdbeEntryMolecules.d.ts +7 -0
- package/dist/pdbeEntryMolecules.js +39 -0
- package/dist/pdbeEntryMolecules.js.map +1 -0
- package/dist/siftsNumbering.d.ts +23 -0
- package/dist/siftsNumbering.js +44 -0
- package/dist/siftsNumbering.js.map +1 -0
- package/dist/stripStopCodon.d.ts +15 -0
- package/dist/stripStopCodon.js +24 -0
- package/dist/stripStopCodon.js.map +1 -0
- package/dist/structureFormat.d.ts +40 -0
- package/dist/structureFormat.js +54 -0
- package/dist/structureFormat.js.map +1 -0
- package/dist/structureSources.d.ts +28 -0
- package/dist/structureSources.js +76 -0
- package/dist/structureSources.js.map +1 -0
- package/dist/structureUrls.d.ts +54 -0
- package/dist/structureUrls.js +147 -0
- package/dist/structureUrls.js.map +1 -0
- package/dist/types.d.ts +14 -0
- package/dist/types.js +27 -0
- package/dist/types.js.map +1 -0
- package/dist/uniProtSearch.d.ts +32 -0
- package/dist/uniProtSearch.js +114 -0
- package/dist/uniProtSearch.js.map +1 -0
- package/esm/alignmentQuality.d.ts +58 -0
- package/esm/alignmentQuality.js +100 -0
- package/esm/alignmentQuality.js.map +1 -0
- package/esm/alphaFoldModels.d.ts +29 -0
- package/esm/alphaFoldModels.js +55 -0
- package/esm/alphaFoldModels.js.map +1 -0
- package/esm/caCoordsToPdb.d.ts +18 -0
- package/esm/caCoordsToPdb.js +91 -0
- package/esm/caCoordsToPdb.js.map +1 -0
- package/esm/chooseMappedEntity.d.ts +55 -0
- package/esm/chooseMappedEntity.js +134 -0
- package/esm/chooseMappedEntity.js.map +1 -0
- package/esm/coordinates.d.ts +66 -0
- package/esm/coordinates.js +58 -0
- package/esm/coordinates.js.map +1 -0
- package/esm/dbIds.d.ts +16 -0
- package/esm/dbIds.js +35 -0
- package/esm/dbIds.js.map +1 -0
- package/esm/extractPerResidueConfidence.d.ts +49 -0
- package/esm/extractPerResidueConfidence.js +38 -0
- package/esm/extractPerResidueConfidence.js.map +1 -0
- package/esm/extractStructureSequences.d.ts +142 -0
- package/esm/extractStructureSequences.js +205 -0
- package/esm/extractStructureSequences.js.map +1 -0
- package/esm/fetchUtils.d.ts +34 -0
- package/esm/fetchUtils.js +82 -0
- package/esm/fetchUtils.js.map +1 -0
- package/esm/index.d.ts +23 -0
- package/esm/index.js +30 -0
- package/esm/index.js.map +1 -0
- package/esm/invertMap.d.ts +2 -0
- package/esm/invertMap.js +5 -0
- package/esm/invertMap.js.map +1 -0
- package/esm/isoformRanking.d.ts +47 -0
- package/esm/isoformRanking.js +86 -0
- package/esm/isoformRanking.js.map +1 -0
- package/esm/mappings.d.ts +58 -0
- package/esm/mappings.js +179 -0
- package/esm/mappings.js.map +1 -0
- package/esm/pairwiseAlignment.d.ts +35 -0
- package/esm/pairwiseAlignment.js +328 -0
- package/esm/pairwiseAlignment.js.map +1 -0
- package/esm/pdbUniProtMapping.d.ts +75 -0
- package/esm/pdbUniProtMapping.js +231 -0
- package/esm/pdbUniProtMapping.js.map +1 -0
- package/esm/pdbeBestStructures.d.ts +23 -0
- package/esm/pdbeBestStructures.js +73 -0
- package/esm/pdbeBestStructures.js.map +1 -0
- package/esm/pdbeEntryMolecules.d.ts +7 -0
- package/esm/pdbeEntryMolecules.js +35 -0
- package/esm/pdbeEntryMolecules.js.map +1 -0
- package/esm/siftsNumbering.d.ts +23 -0
- package/esm/siftsNumbering.js +40 -0
- package/esm/siftsNumbering.js.map +1 -0
- package/esm/stripStopCodon.d.ts +15 -0
- package/esm/stripStopCodon.js +20 -0
- package/esm/stripStopCodon.js.map +1 -0
- package/esm/structureFormat.d.ts +40 -0
- package/esm/structureFormat.js +48 -0
- package/esm/structureFormat.js.map +1 -0
- package/esm/structureSources.d.ts +28 -0
- package/esm/structureSources.js +71 -0
- package/esm/structureSources.js.map +1 -0
- package/esm/structureUrls.d.ts +54 -0
- package/esm/structureUrls.js +134 -0
- package/esm/structureUrls.js.map +1 -0
- package/esm/types.d.ts +14 -0
- package/esm/types.js +23 -0
- package/esm/types.js.map +1 -0
- package/esm/uniProtSearch.d.ts +32 -0
- package/esm/uniProtSearch.js +110 -0
- package/esm/uniProtSearch.js.map +1 -0
- package/package.json +63 -0
- package/src/alignmentQuality.ts +132 -0
- package/src/alphaFoldModels.ts +91 -0
- package/src/caCoordsToPdb.ts +111 -0
- package/src/chooseMappedEntity.ts +198 -0
- package/src/coordinates.ts +119 -0
- package/src/dbIds.ts +46 -0
- package/src/extractPerResidueConfidence.ts +88 -0
- package/src/extractStructureSequences.ts +342 -0
- package/src/fetchUtils.ts +110 -0
- package/src/index.ts +34 -0
- package/src/invertMap.ts +4 -0
- package/src/isoformRanking.ts +139 -0
- package/src/mappings.ts +230 -0
- package/src/pairwiseAlignment.ts +423 -0
- package/src/pdbUniProtMapping.ts +320 -0
- package/src/pdbeBestStructures.ts +94 -0
- package/src/pdbeEntryMolecules.ts +37 -0
- package/src/siftsNumbering.ts +61 -0
- package/src/stripStopCodon.ts +20 -0
- package/src/structureFormat.ts +70 -0
- package/src/structureSources.ts +101 -0
- package/src/structureUrls.ts +171 -0
- package/src/types.ts +30 -0
- package/src/uniProtSearch.ts +212 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
export interface AlignmentRow {
|
|
2
|
+
id: string;
|
|
3
|
+
seq: string;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* A two-row alignment whose ROW ORDER IS A CONTRACT: row 0 is the transcript,
|
|
7
|
+
* row 1 is the structure. Every producer honors it — runLocalAlignment is
|
|
8
|
+
* always called as (transcript, structure), and the manual-import dialog tells
|
|
9
|
+
* the user to paste them in that order — and every consumer depends on it, but
|
|
10
|
+
* nothing in the type can enforce it, and swapping the two silently inverts
|
|
11
|
+
* every coordinate map. Read the rows through the accessors below rather than
|
|
12
|
+
* indexing, so a call site states which sequence it means.
|
|
13
|
+
*/
|
|
14
|
+
export interface PairwiseAlignment {
|
|
15
|
+
consensus: string;
|
|
16
|
+
alns: readonly [AlignmentRow, AlignmentRow];
|
|
17
|
+
}
|
|
18
|
+
export declare const transcriptAlignedSeq: (pa: PairwiseAlignment) => string;
|
|
19
|
+
export declare const structureAlignedSeq: (pa: PairwiseAlignment) => string;
|
|
20
|
+
/** Number of columns, gaps included. Both rows have this length by definition;
|
|
21
|
+
* `pairwiseAlignmentProblem` is what guarantees it. */
|
|
22
|
+
export declare const alignmentLength: (pa: PairwiseAlignment) => number;
|
|
23
|
+
/**
|
|
24
|
+
* Why a pairwise alignment can't be used, or undefined if it's usable. The two
|
|
25
|
+
* rows must be the same non-zero length — every coordinate map walks them in
|
|
26
|
+
* lockstep, so a ragged pair would map positions to nonsense. Callers that
|
|
27
|
+
* accept alignments from outside (the manual-import dialog) check this and
|
|
28
|
+
* report it; the internal map builders assert on it.
|
|
29
|
+
*/
|
|
30
|
+
export declare function pairwiseAlignmentProblem(pa: PairwiseAlignment): string | undefined;
|
|
31
|
+
/**
|
|
32
|
+
* Why an externally supplied alignment does not describe these two sequences,
|
|
33
|
+
* or undefined if it does. The coordinate maps index the transcript and the
|
|
34
|
+
* structure by counting residues along each row, so a row whose residues are
|
|
35
|
+
* not the sequence being mapped (an alignment made against UniProt canonical
|
|
36
|
+
* for a different isoform, or against another chain) shifts every position
|
|
37
|
+
* after the first difference without any map noticing.
|
|
38
|
+
*/
|
|
39
|
+
export declare function pairwiseAlignmentSequenceProblem(pa: PairwiseAlignment, transcript: string, structure: string): string | undefined;
|
|
40
|
+
export declare function structureSeqVsTranscriptSeqMap(pairwiseAlignment: PairwiseAlignment): {
|
|
41
|
+
structureSeqToTranscriptSeqPosition: Record<number, number>;
|
|
42
|
+
transcriptSeqToStructureSeqPosition: Record<number, number>;
|
|
43
|
+
};
|
|
44
|
+
/** Each 0-based structure position opposite a transcript residue, and whether
|
|
45
|
+
* the two residues are identical. */
|
|
46
|
+
export declare function mappedStructureIdentity(pa: PairwiseAlignment): Map<number, boolean>;
|
|
47
|
+
/**
|
|
48
|
+
* The alignment with each listed structure position taken out of its column,
|
|
49
|
+
* so both rows still spell their sequences and those residues map to nothing.
|
|
50
|
+
* An unmapped region, including the gap columns inside it, becomes its
|
|
51
|
+
* transcript residues against gaps, then gaps against its structure residues,
|
|
52
|
+
* rather than alternating column by column. Returns `pa` itself when nothing
|
|
53
|
+
* changes.
|
|
54
|
+
*/
|
|
55
|
+
export declare function unmapStructurePositions(pa: PairwiseAlignment, positions: ReadonlySet<number>): PairwiseAlignment;
|
|
56
|
+
export declare function structurePositionToAlignmentMap(pairwiseAlignment: PairwiseAlignment): Record<number, number>;
|
|
57
|
+
export declare function transcriptPositionToAlignmentMap(pairwiseAlignment: PairwiseAlignment): Record<number, number>;
|
|
58
|
+
export declare function codonGenomeSpan(p2gCodon: Record<number, number[]>, proteinPos: number): readonly [number, number] | undefined;
|
package/dist/mappings.js
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.alignmentLength = exports.structureAlignedSeq = exports.transcriptAlignedSeq = void 0;
|
|
4
|
+
exports.pairwiseAlignmentProblem = pairwiseAlignmentProblem;
|
|
5
|
+
exports.pairwiseAlignmentSequenceProblem = pairwiseAlignmentSequenceProblem;
|
|
6
|
+
exports.structureSeqVsTranscriptSeqMap = structureSeqVsTranscriptSeqMap;
|
|
7
|
+
exports.mappedStructureIdentity = mappedStructureIdentity;
|
|
8
|
+
exports.unmapStructurePositions = unmapStructurePositions;
|
|
9
|
+
exports.structurePositionToAlignmentMap = structurePositionToAlignmentMap;
|
|
10
|
+
exports.transcriptPositionToAlignmentMap = transcriptPositionToAlignmentMap;
|
|
11
|
+
exports.codonGenomeSpan = codonGenomeSpan;
|
|
12
|
+
const g2p_mapper_1 = require("g2p_mapper");
|
|
13
|
+
const transcriptAlignedSeq = (pa) => pa.alns[0].seq;
|
|
14
|
+
exports.transcriptAlignedSeq = transcriptAlignedSeq;
|
|
15
|
+
const structureAlignedSeq = (pa) => pa.alns[1].seq;
|
|
16
|
+
exports.structureAlignedSeq = structureAlignedSeq;
|
|
17
|
+
/** Number of columns, gaps included. Both rows have this length by definition;
|
|
18
|
+
* `pairwiseAlignmentProblem` is what guarantees it. */
|
|
19
|
+
const alignmentLength = (pa) => (0, exports.transcriptAlignedSeq)(pa).length;
|
|
20
|
+
exports.alignmentLength = alignmentLength;
|
|
21
|
+
/**
|
|
22
|
+
* Why a pairwise alignment can't be used, or undefined if it's usable. The two
|
|
23
|
+
* rows must be the same non-zero length — every coordinate map walks them in
|
|
24
|
+
* lockstep, so a ragged pair would map positions to nonsense. Callers that
|
|
25
|
+
* accept alignments from outside (the manual-import dialog) check this and
|
|
26
|
+
* report it; the internal map builders assert on it.
|
|
27
|
+
*/
|
|
28
|
+
function pairwiseAlignmentProblem(pa) {
|
|
29
|
+
const transcript = (0, exports.transcriptAlignedSeq)(pa);
|
|
30
|
+
const structure = (0, exports.structureAlignedSeq)(pa);
|
|
31
|
+
if (transcript.length === 0 || structure.length === 0) {
|
|
32
|
+
return 'The aligned sequences must not be empty';
|
|
33
|
+
}
|
|
34
|
+
if (transcript.length !== structure.length) {
|
|
35
|
+
return `The two aligned sequences must be the same length (got ${transcript.length} and ${structure.length})`;
|
|
36
|
+
}
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
const ungapped = (row) => row.replaceAll('-', '').toUpperCase();
|
|
40
|
+
/**
|
|
41
|
+
* Why an externally supplied alignment does not describe these two sequences,
|
|
42
|
+
* or undefined if it does. The coordinate maps index the transcript and the
|
|
43
|
+
* structure by counting residues along each row, so a row whose residues are
|
|
44
|
+
* not the sequence being mapped (an alignment made against UniProt canonical
|
|
45
|
+
* for a different isoform, or against another chain) shifts every position
|
|
46
|
+
* after the first difference without any map noticing.
|
|
47
|
+
*/
|
|
48
|
+
function pairwiseAlignmentSequenceProblem(pa, transcript, structure) {
|
|
49
|
+
const t = ungapped((0, exports.transcriptAlignedSeq)(pa));
|
|
50
|
+
const s = ungapped((0, exports.structureAlignedSeq)(pa));
|
|
51
|
+
if (t !== transcript.toUpperCase()) {
|
|
52
|
+
return `The first sequence is not this transcript's translation (${t.length} vs ${transcript.length} residues)`;
|
|
53
|
+
}
|
|
54
|
+
if (s !== structure.toUpperCase()) {
|
|
55
|
+
return `The second sequence is not the mapped chain's sequence (${s.length} vs ${structure.length} residues)`;
|
|
56
|
+
}
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
function structureSeqVsTranscriptSeqMap(pairwiseAlignment) {
|
|
60
|
+
const problem = pairwiseAlignmentProblem(pairwiseAlignment);
|
|
61
|
+
if (problem) {
|
|
62
|
+
throw new Error(problem);
|
|
63
|
+
}
|
|
64
|
+
const structureSeq = (0, exports.structureAlignedSeq)(pairwiseAlignment);
|
|
65
|
+
const transcriptSeq = (0, exports.transcriptAlignedSeq)(pairwiseAlignment);
|
|
66
|
+
let j = 0;
|
|
67
|
+
let k = 0;
|
|
68
|
+
const structureSeqToTranscriptSeqPosition = {};
|
|
69
|
+
const transcriptSeqToStructureSeqPosition = {};
|
|
70
|
+
for (let i = 0; i < structureSeq.length; i++) {
|
|
71
|
+
const inStructure = structureSeq[i] !== '-';
|
|
72
|
+
const inTranscript = transcriptSeq[i] !== '-';
|
|
73
|
+
if (inStructure && inTranscript) {
|
|
74
|
+
structureSeqToTranscriptSeqPosition[j] = k;
|
|
75
|
+
transcriptSeqToStructureSeqPosition[k] = j;
|
|
76
|
+
}
|
|
77
|
+
if (inStructure) {
|
|
78
|
+
j++;
|
|
79
|
+
}
|
|
80
|
+
if (inTranscript) {
|
|
81
|
+
k++;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return {
|
|
85
|
+
structureSeqToTranscriptSeqPosition,
|
|
86
|
+
transcriptSeqToStructureSeqPosition,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
/** Each 0-based structure position opposite a transcript residue, and whether
|
|
90
|
+
* the two residues are identical. */
|
|
91
|
+
function mappedStructureIdentity(pa) {
|
|
92
|
+
const transcript = (0, exports.transcriptAlignedSeq)(pa);
|
|
93
|
+
const structure = (0, exports.structureAlignedSeq)(pa);
|
|
94
|
+
const mapped = new Map();
|
|
95
|
+
for (let i = 0, j = 0; i < structure.length; i++) {
|
|
96
|
+
if (structure[i] !== '-') {
|
|
97
|
+
if (transcript[i] !== '-') {
|
|
98
|
+
mapped.set(j, transcript[i].toUpperCase() === structure[i].toUpperCase());
|
|
99
|
+
}
|
|
100
|
+
j++;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return mapped;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* The alignment with each listed structure position taken out of its column,
|
|
107
|
+
* so both rows still spell their sequences and those residues map to nothing.
|
|
108
|
+
* An unmapped region, including the gap columns inside it, becomes its
|
|
109
|
+
* transcript residues against gaps, then gaps against its structure residues,
|
|
110
|
+
* rather than alternating column by column. Returns `pa` itself when nothing
|
|
111
|
+
* changes.
|
|
112
|
+
*/
|
|
113
|
+
function unmapStructurePositions(pa, positions) {
|
|
114
|
+
const transcript = (0, exports.transcriptAlignedSeq)(pa);
|
|
115
|
+
const structure = (0, exports.structureAlignedSeq)(pa);
|
|
116
|
+
const t = [];
|
|
117
|
+
const s = [];
|
|
118
|
+
const c = [];
|
|
119
|
+
const runT = [];
|
|
120
|
+
const runS = [];
|
|
121
|
+
const flushRun = () => {
|
|
122
|
+
t.push(...runT, ...runS.map(() => '-'));
|
|
123
|
+
s.push(...runT.map(() => '-'), ...runS);
|
|
124
|
+
c.push(...runT.map(() => ' '), ...runS.map(() => ' '));
|
|
125
|
+
runT.length = 0;
|
|
126
|
+
runS.length = 0;
|
|
127
|
+
};
|
|
128
|
+
let j = 0;
|
|
129
|
+
let changed = false;
|
|
130
|
+
for (let i = 0; i < structure.length; i++) {
|
|
131
|
+
const inStructure = structure[i] !== '-';
|
|
132
|
+
const inTranscript = transcript[i] !== '-';
|
|
133
|
+
if (inStructure && inTranscript && positions.has(j)) {
|
|
134
|
+
runT.push(transcript[i]);
|
|
135
|
+
runS.push(structure[i]);
|
|
136
|
+
changed = true;
|
|
137
|
+
}
|
|
138
|
+
else if (runT.length > 0 && !(inStructure && inTranscript)) {
|
|
139
|
+
if (inTranscript) {
|
|
140
|
+
runT.push(transcript[i]);
|
|
141
|
+
}
|
|
142
|
+
if (inStructure) {
|
|
143
|
+
runS.push(structure[i]);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
flushRun();
|
|
148
|
+
t.push(transcript[i]);
|
|
149
|
+
s.push(structure[i]);
|
|
150
|
+
c.push(pa.consensus[i] ?? ' ');
|
|
151
|
+
}
|
|
152
|
+
if (inStructure) {
|
|
153
|
+
j++;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
flushRun();
|
|
157
|
+
return changed
|
|
158
|
+
? {
|
|
159
|
+
consensus: c.join(''),
|
|
160
|
+
alns: [
|
|
161
|
+
{ ...pa.alns[0], seq: t.join('') },
|
|
162
|
+
{ ...pa.alns[1], seq: s.join('') },
|
|
163
|
+
],
|
|
164
|
+
}
|
|
165
|
+
: pa;
|
|
166
|
+
}
|
|
167
|
+
function seqPositionToAlignmentMap(seq) {
|
|
168
|
+
const map = {};
|
|
169
|
+
for (let i = 0, j = 0; i < seq.length; i++) {
|
|
170
|
+
if (seq[i] !== '-') {
|
|
171
|
+
map[j] = i;
|
|
172
|
+
j++;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return map;
|
|
176
|
+
}
|
|
177
|
+
function structurePositionToAlignmentMap(pairwiseAlignment) {
|
|
178
|
+
return seqPositionToAlignmentMap((0, exports.structureAlignedSeq)(pairwiseAlignment));
|
|
179
|
+
}
|
|
180
|
+
function transcriptPositionToAlignmentMap(pairwiseAlignment) {
|
|
181
|
+
return seqPositionToAlignmentMap((0, exports.transcriptAlignedSeq)(pairwiseAlignment));
|
|
182
|
+
}
|
|
183
|
+
// Enclosing 0-based half-open [start, end) genome span for a codon. getCodonRanges
|
|
184
|
+
// returns the codon's separate genomic pieces (multiple when it straddles an
|
|
185
|
+
// exon/intron boundary); this collapses them to the outer span for navigation
|
|
186
|
+
// and highlighting. undefined when the protein position isn't mapped.
|
|
187
|
+
function codonGenomeSpan(p2gCodon, proteinPos) {
|
|
188
|
+
const ranges = (0, g2p_mapper_1.getCodonRanges)(p2gCodon, proteinPos);
|
|
189
|
+
return ranges && ranges.length > 0
|
|
190
|
+
? [Math.min(...ranges.map(r => r[0])), Math.max(...ranges.map(r => r[1]))]
|
|
191
|
+
: undefined;
|
|
192
|
+
}
|
|
193
|
+
//# sourceMappingURL=mappings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mappings.js","sourceRoot":"","sources":["../src/mappings.ts"],"names":[],"mappings":";;;AAoCA,4DAUC;AAYD,4EAcC;AAED,wEAkCC;AAID,0DAgBC;AAUD,0DAsDC;AAaD,0EAIC;AAED,4EAIC;AAMD,0CAQC;AArOD,2CAA2C;AAqBpC,MAAM,oBAAoB,GAAG,CAAC,EAAqB,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAA;AAAhE,QAAA,oBAAoB,wBAA4C;AACtE,MAAM,mBAAmB,GAAG,CAAC,EAAqB,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAA;AAA/D,QAAA,mBAAmB,uBAA4C;AAE5E;uDACuD;AAChD,MAAM,eAAe,GAAG,CAAC,EAAqB,EAAE,EAAE,CACvD,IAAA,4BAAoB,EAAC,EAAE,CAAC,CAAC,MAAM,CAAA;AADpB,QAAA,eAAe,mBACK;AAEjC;;;;;;GAMG;AACH,SAAgB,wBAAwB,CAAC,EAAqB;IAC5D,MAAM,UAAU,GAAG,IAAA,4BAAoB,EAAC,EAAE,CAAC,CAAA;IAC3C,MAAM,SAAS,GAAG,IAAA,2BAAmB,EAAC,EAAE,CAAC,CAAA;IACzC,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtD,OAAO,yCAAyC,CAAA;IAClD,CAAC;IACD,IAAI,UAAU,CAAC,MAAM,KAAK,SAAS,CAAC,MAAM,EAAE,CAAC;QAC3C,OAAO,0DAA0D,UAAU,CAAC,MAAM,QAAQ,SAAS,CAAC,MAAM,GAAG,CAAA;IAC/G,CAAC;IACD,OAAO,SAAS,CAAA;AAClB,CAAC;AAED,MAAM,QAAQ,GAAG,CAAC,GAAW,EAAE,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,WAAW,EAAE,CAAA;AAEvE;;;;;;;GAOG;AACH,SAAgB,gCAAgC,CAC9C,EAAqB,EACrB,UAAkB,EAClB,SAAiB;IAEjB,MAAM,CAAC,GAAG,QAAQ,CAAC,IAAA,4BAAoB,EAAC,EAAE,CAAC,CAAC,CAAA;IAC5C,MAAM,CAAC,GAAG,QAAQ,CAAC,IAAA,2BAAmB,EAAC,EAAE,CAAC,CAAC,CAAA;IAC3C,IAAI,CAAC,KAAK,UAAU,CAAC,WAAW,EAAE,EAAE,CAAC;QACnC,OAAO,4DAA4D,CAAC,CAAC,MAAM,OAAO,UAAU,CAAC,MAAM,YAAY,CAAA;IACjH,CAAC;IACD,IAAI,CAAC,KAAK,SAAS,CAAC,WAAW,EAAE,EAAE,CAAC;QAClC,OAAO,2DAA2D,CAAC,CAAC,MAAM,OAAO,SAAS,CAAC,MAAM,YAAY,CAAA;IAC/G,CAAC;IACD,OAAO,SAAS,CAAA;AAClB,CAAC;AAED,SAAgB,8BAA8B,CAC5C,iBAAoC;IAEpC,MAAM,OAAO,GAAG,wBAAwB,CAAC,iBAAiB,CAAC,CAAA;IAC3D,IAAI,OAAO,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAA;IAC1B,CAAC;IACD,MAAM,YAAY,GAAG,IAAA,2BAAmB,EAAC,iBAAiB,CAAC,CAAA;IAC3D,MAAM,aAAa,GAAG,IAAA,4BAAoB,EAAC,iBAAiB,CAAC,CAAA;IAE7D,IAAI,CAAC,GAAG,CAAC,CAAA;IACT,IAAI,CAAC,GAAG,CAAC,CAAA;IACT,MAAM,mCAAmC,GAA2B,EAAE,CAAA;IACtE,MAAM,mCAAmC,GAA2B,EAAE,CAAA;IAEtE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,YAAY,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC7C,MAAM,WAAW,GAAG,YAAY,CAAC,CAAC,CAAC,KAAK,GAAG,CAAA;QAC3C,MAAM,YAAY,GAAG,aAAa,CAAC,CAAC,CAAC,KAAK,GAAG,CAAA;QAC7C,IAAI,WAAW,IAAI,YAAY,EAAE,CAAC;YAChC,mCAAmC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;YAC1C,mCAAmC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;QAC5C,CAAC;QACD,IAAI,WAAW,EAAE,CAAC;YAChB,CAAC,EAAE,CAAA;QACL,CAAC;QACD,IAAI,YAAY,EAAE,CAAC;YACjB,CAAC,EAAE,CAAA;QACL,CAAC;IACH,CAAC;IAED,OAAO;QACL,mCAAmC;QACnC,mCAAmC;KACpC,CAAA;AACH,CAAC;AAED;qCACqC;AACrC,SAAgB,uBAAuB,CAAC,EAAqB;IAC3D,MAAM,UAAU,GAAG,IAAA,4BAAoB,EAAC,EAAE,CAAC,CAAA;IAC3C,MAAM,SAAS,GAAG,IAAA,2BAAmB,EAAC,EAAE,CAAC,CAAA;IACzC,MAAM,MAAM,GAAG,IAAI,GAAG,EAAmB,CAAA;IACzC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACjD,IAAI,SAAS,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;YACzB,IAAI,UAAU,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;gBAC1B,MAAM,CAAC,GAAG,CACR,CAAC,EACD,UAAU,CAAC,CAAC,CAAE,CAAC,WAAW,EAAE,KAAK,SAAS,CAAC,CAAC,CAAE,CAAC,WAAW,EAAE,CAC7D,CAAA;YACH,CAAC;YACD,CAAC,EAAE,CAAA;QACL,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAA;AACf,CAAC;AAED;;;;;;;GAOG;AACH,SAAgB,uBAAuB,CACrC,EAAqB,EACrB,SAA8B;IAE9B,MAAM,UAAU,GAAG,IAAA,4BAAoB,EAAC,EAAE,CAAC,CAAA;IAC3C,MAAM,SAAS,GAAG,IAAA,2BAAmB,EAAC,EAAE,CAAC,CAAA;IACzC,MAAM,CAAC,GAAa,EAAE,CAAA;IACtB,MAAM,CAAC,GAAa,EAAE,CAAA;IACtB,MAAM,CAAC,GAAa,EAAE,CAAA;IACtB,MAAM,IAAI,GAAa,EAAE,CAAA;IACzB,MAAM,IAAI,GAAa,EAAE,CAAA;IACzB,MAAM,QAAQ,GAAG,GAAG,EAAE;QACpB,CAAC,CAAC,IAAI,CAAC,GAAG,IAAI,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAA;QACvC,CAAC,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,EAAE,GAAG,IAAI,CAAC,CAAA;QACvC,CAAC,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAA;QACtD,IAAI,CAAC,MAAM,GAAG,CAAC,CAAA;QACf,IAAI,CAAC,MAAM,GAAG,CAAC,CAAA;IACjB,CAAC,CAAA;IACD,IAAI,CAAC,GAAG,CAAC,CAAA;IACT,IAAI,OAAO,GAAG,KAAK,CAAA;IACnB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC1C,MAAM,WAAW,GAAG,SAAS,CAAC,CAAC,CAAC,KAAK,GAAG,CAAA;QACxC,MAAM,YAAY,GAAG,UAAU,CAAC,CAAC,CAAC,KAAK,GAAG,CAAA;QAC1C,IAAI,WAAW,IAAI,YAAY,IAAI,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;YACpD,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAE,CAAC,CAAA;YACzB,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAE,CAAC,CAAA;YACxB,OAAO,GAAG,IAAI,CAAA;QAChB,CAAC;aAAM,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,CAAC,WAAW,IAAI,YAAY,CAAC,EAAE,CAAC;YAC7D,IAAI,YAAY,EAAE,CAAC;gBACjB,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAE,CAAC,CAAA;YAC3B,CAAC;YACD,IAAI,WAAW,EAAE,CAAC;gBAChB,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAE,CAAC,CAAA;YAC1B,CAAC;QACH,CAAC;aAAM,CAAC;YACN,QAAQ,EAAE,CAAA;YACV,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAE,CAAC,CAAA;YACtB,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAE,CAAC,CAAA;YACrB,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAA;QAChC,CAAC;QACD,IAAI,WAAW,EAAE,CAAC;YAChB,CAAC,EAAE,CAAA;QACL,CAAC;IACH,CAAC;IACD,QAAQ,EAAE,CAAA;IACV,OAAO,OAAO;QACZ,CAAC,CAAC;YACE,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;YACrB,IAAI,EAAE;gBACJ,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE;gBAClC,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE;aACnC;SACF;QACH,CAAC,CAAC,EAAE,CAAA;AACR,CAAC;AAED,SAAS,yBAAyB,CAAC,GAAW;IAC5C,MAAM,GAAG,GAA2B,EAAE,CAAA;IACtC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3C,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;YACnB,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;YACV,CAAC,EAAE,CAAA;QACL,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC;AAED,SAAgB,+BAA+B,CAC7C,iBAAoC;IAEpC,OAAO,yBAAyB,CAAC,IAAA,2BAAmB,EAAC,iBAAiB,CAAC,CAAC,CAAA;AAC1E,CAAC;AAED,SAAgB,gCAAgC,CAC9C,iBAAoC;IAEpC,OAAO,yBAAyB,CAAC,IAAA,4BAAoB,EAAC,iBAAiB,CAAC,CAAC,CAAA;AAC3E,CAAC;AAED,mFAAmF;AACnF,6EAA6E;AAC7E,8EAA8E;AAC9E,sEAAsE;AACtE,SAAgB,eAAe,CAC7B,QAAkC,EAClC,UAAkB;IAElB,MAAM,MAAM,GAAG,IAAA,2BAAc,EAAC,QAAQ,EAAE,UAAU,CAAC,CAAA;IACnD,OAAO,MAAM,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC;QAChC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1E,CAAC,CAAC,SAAS,CAAA;AACf,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type": "commonjs"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { PairwiseAlignment } from './mappings.ts';
|
|
2
|
+
import type { AlignmentAlgorithm } from './types.ts';
|
|
3
|
+
interface AlignmentResult {
|
|
4
|
+
alignedSeq1: string;
|
|
5
|
+
alignedSeq2: string;
|
|
6
|
+
score: number;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Ceiling on the dynamic-programming table, in cells. Both algorithms are
|
|
10
|
+
* O(m*n) time and hold one byte of traceback per cell, so this bounds the
|
|
11
|
+
* alignment at ~40 MB and roughly a second of main-thread work. Without it a
|
|
12
|
+
* titin-sized transcript or a long nucleic-acid chain locks up or OOMs the tab.
|
|
13
|
+
* Callers that have several candidates to align should check `alignmentTooLarge`
|
|
14
|
+
* and skip the oversized ones rather than let this throw.
|
|
15
|
+
*/
|
|
16
|
+
export declare const MAX_ALIGNMENT_CELLS = 40000000;
|
|
17
|
+
export declare function alignmentTooLarge(len1: number, len2: number): boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Needleman-Wunsch global alignment algorithm
|
|
20
|
+
* Aligns entire sequences end-to-end
|
|
21
|
+
*/
|
|
22
|
+
export declare function needlemanWunsch(seq1: string, seq2: string, gapOpen?: number, gapExtend?: number): AlignmentResult;
|
|
23
|
+
/**
|
|
24
|
+
* Smith-Waterman local alignment algorithm
|
|
25
|
+
* Finds the best local alignment between subsequences
|
|
26
|
+
*/
|
|
27
|
+
export declare function smithWaterman(seq1: string, seq2: string, gapOpen?: number, gapExtend?: number): AlignmentResult;
|
|
28
|
+
/** The score of a sequence aligned to itself with no gaps. */
|
|
29
|
+
export declare function selfScore(seq: string): number;
|
|
30
|
+
export declare function scoredAlignment(seq1: string, seq2: string, algorithm: AlignmentAlgorithm): {
|
|
31
|
+
alignment: PairwiseAlignment;
|
|
32
|
+
score: number;
|
|
33
|
+
};
|
|
34
|
+
export declare function runLocalAlignment(seq1: string, seq2: string, algorithm: AlignmentAlgorithm): PairwiseAlignment;
|
|
35
|
+
export {};
|
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MAX_ALIGNMENT_CELLS = void 0;
|
|
4
|
+
exports.alignmentTooLarge = alignmentTooLarge;
|
|
5
|
+
exports.needlemanWunsch = needlemanWunsch;
|
|
6
|
+
exports.smithWaterman = smithWaterman;
|
|
7
|
+
exports.selfScore = selfScore;
|
|
8
|
+
exports.scoredAlignment = scoredAlignment;
|
|
9
|
+
exports.runLocalAlignment = runLocalAlignment;
|
|
10
|
+
// BLOSUM62 scoring matrix — standard 20 amino acids + B, Z, X, *
|
|
11
|
+
// prettier-ignore
|
|
12
|
+
const AMINO_ACIDS = ['A', 'R', 'N', 'D', 'C', 'Q', 'E', 'G', 'H', 'I', 'L', 'K', 'M', 'F', 'P', 'S', 'T', 'W', 'Y', 'V', 'B', 'Z', 'X', '*'];
|
|
13
|
+
// prettier-ignore
|
|
14
|
+
const BLOSUM62_RAW = [
|
|
15
|
+
// A R N D C Q E G H I L K M F P S T W Y V B Z X *
|
|
16
|
+
[4, -1, -2, -2, 0, -1, -1, 0, -2, -1, -1, -1, -1, -2, -1, 1, 0, -3, -2, 0, -2, -1, 0, -4], // A
|
|
17
|
+
[-1, 5, 0, -2, -3, 1, 0, -2, 0, -3, -2, 2, -1, -3, -2, -1, -1, -3, -2, -3, -1, 0, -1, -4], // R
|
|
18
|
+
[-2, 0, 6, 1, -3, 0, 0, 0, 1, -3, -3, 0, -2, -3, -2, 1, 0, -4, -2, -3, 3, 0, -1, -4], // N
|
|
19
|
+
[-2, -2, 1, 6, -3, 0, 2, -1, -1, -3, -4, -1, -3, -3, -1, 0, -1, -4, -3, -3, 4, 1, -1, -4], // D
|
|
20
|
+
[0, -3, -3, -3, 9, -3, -4, -3, -3, -1, -1, -3, -1, -2, -3, -1, -1, -2, -2, -1, -3, -3, -2, -4], // C
|
|
21
|
+
[-1, 1, 0, 0, -3, 5, 2, -2, 0, -3, -2, 1, 0, -3, -1, 0, -1, -2, -1, -2, 0, 3, -1, -4], // Q
|
|
22
|
+
[-1, 0, 0, 2, -4, 2, 5, -2, 0, -3, -3, 1, -2, -3, -1, 0, -1, -3, -2, -2, 1, 4, -1, -4], // E
|
|
23
|
+
[0, -2, 0, -1, -3, -2, -2, 6, -2, -4, -4, -2, -3, -3, -2, 0, -2, -2, -3, -3, -1, -2, -1, -4], // G
|
|
24
|
+
[-2, 0, 1, -1, -3, 0, 0, -2, 8, -3, -3, -1, -2, -1, -2, -1, -2, -2, 2, -3, 0, 0, -1, -4], // H
|
|
25
|
+
[-1, -3, -3, -3, -1, -3, -3, -4, -3, 4, 2, -3, 1, 0, -3, -2, -1, -3, -1, 3, -3, -3, -1, -4], // I
|
|
26
|
+
[-1, -2, -3, -4, -1, -2, -3, -4, -3, 2, 4, -2, 2, 0, -3, -2, -1, -2, -1, 1, -4, -3, -1, -4], // L
|
|
27
|
+
[-1, 2, 0, -1, -3, 1, 1, -2, -1, -3, -2, 5, -1, -3, -1, 0, -1, -3, -2, -2, 0, 1, -1, -4], // K
|
|
28
|
+
[-1, -1, -2, -3, -1, 0, -2, -3, -2, 1, 2, -1, 5, 0, -2, -1, -1, -1, -1, 1, -3, -1, -1, -4], // M
|
|
29
|
+
[-2, -3, -3, -3, -2, -3, -3, -3, -1, 0, 0, -3, 0, 6, -4, -2, -2, 1, 3, -1, -3, -3, -1, -4], // F
|
|
30
|
+
[-1, -2, -2, -1, -3, -1, -1, -2, -2, -3, -3, -1, -2, -4, 7, -1, -1, -4, -3, -2, -2, -1, -2, -4], // P
|
|
31
|
+
[1, -1, 1, 0, -1, 0, 0, 0, -1, -2, -2, 0, -1, -2, -1, 4, 1, -3, -2, -2, 0, 0, 0, -4], // S
|
|
32
|
+
[0, -1, 0, -1, -1, -1, -1, -2, -2, -1, -1, -1, -1, -2, -1, 1, 5, -2, -2, 0, -1, -1, 0, -4], // T
|
|
33
|
+
[-3, -3, -4, -4, -2, -2, -3, -2, -2, -3, -2, -3, -1, 1, -4, -3, -2, 11, 2, -3, -4, -3, -2, -4], // W
|
|
34
|
+
[-2, -2, -2, -3, -2, -1, -2, -3, 2, -1, -1, -2, -1, 3, -3, -2, -2, 2, 7, -1, -3, -2, -1, -4], // Y
|
|
35
|
+
[0, -3, -3, -3, -1, -2, -2, -3, -3, 3, 1, -2, 1, -1, -2, -2, 0, -3, -1, 4, -3, -2, -1, -4], // V
|
|
36
|
+
[-2, -1, 3, 4, -3, 0, 1, -1, 0, -3, -4, 0, -3, -3, -2, 0, -1, -4, -3, -3, 4, 1, -1, -4], // B
|
|
37
|
+
[-1, 0, 0, 1, -3, 3, 4, -2, 0, -3, -3, 1, -1, -3, -1, 0, -1, -3, -2, -2, 1, 4, -1, -4], // Z
|
|
38
|
+
[0, -1, -1, -1, -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, 0, 0, -2, -1, -1, -1, -1, -1, -4], // X
|
|
39
|
+
[-4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, 1], // *
|
|
40
|
+
];
|
|
41
|
+
// Score of a residue pair that isn't in the matrix at all.
|
|
42
|
+
const UNKNOWN_PAIR_SCORE = -4;
|
|
43
|
+
// The DP reads the matrix once per cell, so both the residue→row lookup and the
|
|
44
|
+
// matrix itself are flat typed arrays keyed by char code: charCodeToRow maps
|
|
45
|
+
// 'a'/'A' to the same row, and unknown residues to -1 (scored as unknown).
|
|
46
|
+
const N_AA = AMINO_ACIDS.length;
|
|
47
|
+
const charCodeToRow = new Int8Array(128).fill(-1);
|
|
48
|
+
for (let i = 0; i < N_AA; i++) {
|
|
49
|
+
const aa = AMINO_ACIDS[i];
|
|
50
|
+
charCodeToRow[aa.charCodeAt(0)] = i;
|
|
51
|
+
charCodeToRow[aa.toLowerCase().charCodeAt(0)] = i;
|
|
52
|
+
}
|
|
53
|
+
const BLOSUM62 = new Int8Array(N_AA * N_AA);
|
|
54
|
+
for (let i = 0; i < N_AA; i++) {
|
|
55
|
+
for (let j = 0; j < N_AA; j++) {
|
|
56
|
+
BLOSUM62[i * N_AA + j] = BLOSUM62_RAW[i][j];
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const rowOf = (c) => {
|
|
60
|
+
const code = c.charCodeAt(0);
|
|
61
|
+
return code < 128 ? charCodeToRow[code] : -1;
|
|
62
|
+
};
|
|
63
|
+
function getScore(a, b) {
|
|
64
|
+
const i = rowOf(a);
|
|
65
|
+
const j = rowOf(b);
|
|
66
|
+
return i < 0 || j < 0 ? UNKNOWN_PAIR_SCORE : BLOSUM62[i * N_AA + j];
|
|
67
|
+
}
|
|
68
|
+
// Default gap penalties (matching EMBOSS defaults)
|
|
69
|
+
const GAP_OPEN = -10;
|
|
70
|
+
const GAP_EXTEND = -0.5;
|
|
71
|
+
/**
|
|
72
|
+
* Ceiling on the dynamic-programming table, in cells. Both algorithms are
|
|
73
|
+
* O(m*n) time and hold one byte of traceback per cell, so this bounds the
|
|
74
|
+
* alignment at ~40 MB and roughly a second of main-thread work. Without it a
|
|
75
|
+
* titin-sized transcript or a long nucleic-acid chain locks up or OOMs the tab.
|
|
76
|
+
* Callers that have several candidates to align should check `alignmentTooLarge`
|
|
77
|
+
* and skip the oversized ones rather than let this throw.
|
|
78
|
+
*/
|
|
79
|
+
exports.MAX_ALIGNMENT_CELLS = 40_000_000;
|
|
80
|
+
function alignmentTooLarge(len1, len2) {
|
|
81
|
+
return (len1 + 1) * (len2 + 1) > exports.MAX_ALIGNMENT_CELLS;
|
|
82
|
+
}
|
|
83
|
+
function assertAlignable(len1, len2) {
|
|
84
|
+
if (alignmentTooLarge(len1, len2)) {
|
|
85
|
+
throw new Error(`Sequences too long to align (${len1} x ${len2} residues exceeds the ${exports.MAX_ALIGNMENT_CELLS} cell limit)`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
// Traceback states. Each cell stores, for each of the three matrices, which
|
|
89
|
+
// matrix its best predecessor came from — 2 bits per matrix, packed into one
|
|
90
|
+
// byte. Storing pointers instead of re-deriving them by comparing scores keeps
|
|
91
|
+
// traceback exact under Float32 rounding and lets the score matrices collapse
|
|
92
|
+
// to two rows.
|
|
93
|
+
const FROM_M = 0;
|
|
94
|
+
const FROM_IX = 1;
|
|
95
|
+
const FROM_IY = 2;
|
|
96
|
+
// Smith-Waterman only: the local alignment restarts here, so traceback stops.
|
|
97
|
+
const FROM_NONE = 3;
|
|
98
|
+
const M_SHIFT = 0;
|
|
99
|
+
const IX_SHIFT = 2;
|
|
100
|
+
const IY_SHIFT = 4;
|
|
101
|
+
const readPointer = (trace, at, shift) => ((trace[at] >> shift) & 0b11);
|
|
102
|
+
/**
|
|
103
|
+
* Fill the affine-gap DP tables for both algorithms; `local` switches
|
|
104
|
+
* Needleman-Wunsch (global, ends at the corner) to Smith-Waterman (restarts at
|
|
105
|
+
* 0, ends at the best-scoring cell). Only the previous and current score rows
|
|
106
|
+
* are kept — the full traceback lives in the packed `trace` byte array.
|
|
107
|
+
*/
|
|
108
|
+
function fillMatrices(seq1, seq2, gapOpen, gapExtend, local) {
|
|
109
|
+
const m = seq1.length;
|
|
110
|
+
const n = seq2.length;
|
|
111
|
+
assertAlignable(m, n);
|
|
112
|
+
const width = n + 1;
|
|
113
|
+
const trace = new Uint8Array((m + 1) * width);
|
|
114
|
+
// Row 0. Global: only M[0][0] is reachable and Iy[0][j] is the leading-gap
|
|
115
|
+
// base case. Local: M starts at 0 everywhere, gaps are unreachable.
|
|
116
|
+
let prevM = new Float32Array(width);
|
|
117
|
+
let prevIx = new Float32Array(width).fill(-Infinity);
|
|
118
|
+
let prevIy = new Float32Array(width).fill(-Infinity);
|
|
119
|
+
let curM = new Float32Array(width);
|
|
120
|
+
let curIx = new Float32Array(width);
|
|
121
|
+
let curIy = new Float32Array(width);
|
|
122
|
+
if (!local) {
|
|
123
|
+
prevM.fill(-Infinity);
|
|
124
|
+
prevM[0] = 0;
|
|
125
|
+
for (let j = 1; j <= n; j++) {
|
|
126
|
+
prevIy[j] = gapOpen + (j - 1) * gapExtend;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
let bestScore = local ? 0 : -Infinity;
|
|
130
|
+
let bestI = 0;
|
|
131
|
+
let bestJ = 0;
|
|
132
|
+
let bestMatrix = FROM_M;
|
|
133
|
+
// Resolve seq2 to matrix rows once instead of once per cell.
|
|
134
|
+
const cols = new Int8Array(n);
|
|
135
|
+
for (let j = 0; j < n; j++) {
|
|
136
|
+
cols[j] = rowOf(seq2[j]);
|
|
137
|
+
}
|
|
138
|
+
for (let i = 1; i <= m; i++) {
|
|
139
|
+
// Column 0, mirroring row 0.
|
|
140
|
+
curM[0] = local ? 0 : -Infinity;
|
|
141
|
+
curIx[0] = local ? -Infinity : gapOpen + (i - 1) * gapExtend;
|
|
142
|
+
curIy[0] = -Infinity;
|
|
143
|
+
const rowBase = i * width;
|
|
144
|
+
const scoreRow = rowOf(seq1[i - 1]);
|
|
145
|
+
const scoreBase = scoreRow * N_AA;
|
|
146
|
+
for (let j = 1; j <= n; j++) {
|
|
147
|
+
const col = cols[j - 1];
|
|
148
|
+
const matchScore = scoreRow < 0 || col < 0
|
|
149
|
+
? UNKNOWN_PAIR_SCORE
|
|
150
|
+
: BLOSUM62[scoreBase + col];
|
|
151
|
+
const dM = prevM[j - 1];
|
|
152
|
+
const dIx = prevIx[j - 1];
|
|
153
|
+
const dIy = prevIy[j - 1];
|
|
154
|
+
// Ties resolve M > Ix > Iy, matching the previous implementation.
|
|
155
|
+
const bestDiag = Math.max(dM, dIx, dIy);
|
|
156
|
+
const diagFrom = bestDiag === dM ? FROM_M : bestDiag === dIx ? FROM_IX : FROM_IY;
|
|
157
|
+
const mScore = bestDiag + matchScore;
|
|
158
|
+
const restart = local && mScore <= 0;
|
|
159
|
+
curM[j] = restart ? 0 : mScore;
|
|
160
|
+
const openIx = prevM[j] + gapOpen;
|
|
161
|
+
const extendIx = prevIx[j] + gapExtend;
|
|
162
|
+
curIx[j] = Math.max(openIx, extendIx);
|
|
163
|
+
const openIy = curM[j - 1] + gapOpen;
|
|
164
|
+
const extendIy = curIy[j - 1] + gapExtend;
|
|
165
|
+
curIy[j] = Math.max(openIy, extendIy);
|
|
166
|
+
trace[rowBase + j] =
|
|
167
|
+
((restart ? FROM_NONE : diagFrom) << M_SHIFT) |
|
|
168
|
+
((openIx >= extendIx ? FROM_M : FROM_IX) << IX_SHIFT) |
|
|
169
|
+
((openIy >= extendIy ? FROM_M : FROM_IY) << IY_SHIFT);
|
|
170
|
+
if (local) {
|
|
171
|
+
const cellMax = Math.max(curM[j], curIx[j], curIy[j]);
|
|
172
|
+
if (cellMax > bestScore) {
|
|
173
|
+
bestScore = cellMax;
|
|
174
|
+
bestI = i;
|
|
175
|
+
bestJ = j;
|
|
176
|
+
bestMatrix =
|
|
177
|
+
cellMax === curM[j]
|
|
178
|
+
? FROM_M
|
|
179
|
+
: cellMax === curIx[j]
|
|
180
|
+
? FROM_IX
|
|
181
|
+
: FROM_IY;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
;
|
|
186
|
+
[prevM, curM] = [curM, prevM];
|
|
187
|
+
[prevIx, curIx] = [curIx, prevIx];
|
|
188
|
+
[prevIy, curIy] = [curIy, prevIy];
|
|
189
|
+
}
|
|
190
|
+
if (local) {
|
|
191
|
+
return {
|
|
192
|
+
trace,
|
|
193
|
+
width,
|
|
194
|
+
score: bestScore,
|
|
195
|
+
startI: bestI,
|
|
196
|
+
startJ: bestJ,
|
|
197
|
+
startMatrix: bestMatrix,
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
// prev* now holds row m.
|
|
201
|
+
const finalM = prevM[n];
|
|
202
|
+
const finalIx = prevIx[n];
|
|
203
|
+
const finalIy = prevIy[n];
|
|
204
|
+
const score = Math.max(finalM, finalIx, finalIy);
|
|
205
|
+
return {
|
|
206
|
+
trace,
|
|
207
|
+
width,
|
|
208
|
+
score,
|
|
209
|
+
startI: m,
|
|
210
|
+
startJ: n,
|
|
211
|
+
startMatrix: score === finalM ? FROM_M : score === finalIx ? FROM_IX : FROM_IY,
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Walk the packed traceback back to an edge. Rows are built back-to-front into
|
|
216
|
+
* arrays and reversed once, rather than prepending onto a string per residue
|
|
217
|
+
* (which is quadratic in the alignment length).
|
|
218
|
+
*/
|
|
219
|
+
function traceback(seq1, seq2, filled) {
|
|
220
|
+
const { trace, width, startI, startJ, score } = filled;
|
|
221
|
+
// Reversed: pushing here is prepending to the final string.
|
|
222
|
+
const out1 = [];
|
|
223
|
+
const out2 = [];
|
|
224
|
+
// Residues past the aligned region (the whole sequences when the local
|
|
225
|
+
// alignment is empty) hang off the end as gaps.
|
|
226
|
+
for (let k = seq1.length; k > startI; k--) {
|
|
227
|
+
out1.push(seq1[k - 1]);
|
|
228
|
+
out2.push('-');
|
|
229
|
+
}
|
|
230
|
+
for (let k = seq2.length; k > startJ; k--) {
|
|
231
|
+
out1.push('-');
|
|
232
|
+
out2.push(seq2[k - 1]);
|
|
233
|
+
}
|
|
234
|
+
let i = startI;
|
|
235
|
+
let j = startJ;
|
|
236
|
+
let matrix = filled.startMatrix;
|
|
237
|
+
while (i > 0 && j > 0) {
|
|
238
|
+
const at = i * width + j;
|
|
239
|
+
if (matrix === FROM_M) {
|
|
240
|
+
const next = readPointer(trace, at, M_SHIFT);
|
|
241
|
+
if (next === FROM_NONE) {
|
|
242
|
+
break;
|
|
243
|
+
}
|
|
244
|
+
out1.push(seq1[i - 1]);
|
|
245
|
+
out2.push(seq2[j - 1]);
|
|
246
|
+
matrix = next;
|
|
247
|
+
i--;
|
|
248
|
+
j--;
|
|
249
|
+
}
|
|
250
|
+
else if (matrix === FROM_IX) {
|
|
251
|
+
out1.push(seq1[i - 1]);
|
|
252
|
+
out2.push('-');
|
|
253
|
+
matrix = readPointer(trace, at, IX_SHIFT);
|
|
254
|
+
i--;
|
|
255
|
+
}
|
|
256
|
+
else {
|
|
257
|
+
out1.push('-');
|
|
258
|
+
out2.push(seq2[j - 1]);
|
|
259
|
+
matrix = readPointer(trace, at, IY_SHIFT);
|
|
260
|
+
j--;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
// Whatever is left runs into an edge, so it can only be gaps.
|
|
264
|
+
while (i > 0) {
|
|
265
|
+
out1.push(seq1[i - 1]);
|
|
266
|
+
out2.push('-');
|
|
267
|
+
i--;
|
|
268
|
+
}
|
|
269
|
+
while (j > 0) {
|
|
270
|
+
out1.push('-');
|
|
271
|
+
out2.push(seq2[j - 1]);
|
|
272
|
+
j--;
|
|
273
|
+
}
|
|
274
|
+
return {
|
|
275
|
+
alignedSeq1: out1.reverse().join(''),
|
|
276
|
+
alignedSeq2: out2.reverse().join(''),
|
|
277
|
+
score,
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Needleman-Wunsch global alignment algorithm
|
|
282
|
+
* Aligns entire sequences end-to-end
|
|
283
|
+
*/
|
|
284
|
+
function needlemanWunsch(seq1, seq2, gapOpen = GAP_OPEN, gapExtend = GAP_EXTEND) {
|
|
285
|
+
return traceback(seq1, seq2, fillMatrices(seq1, seq2, gapOpen, gapExtend, false));
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Smith-Waterman local alignment algorithm
|
|
289
|
+
* Finds the best local alignment between subsequences
|
|
290
|
+
*/
|
|
291
|
+
function smithWaterman(seq1, seq2, gapOpen = GAP_OPEN, gapExtend = GAP_EXTEND) {
|
|
292
|
+
return traceback(seq1, seq2, fillMatrices(seq1, seq2, gapOpen, gapExtend, true));
|
|
293
|
+
}
|
|
294
|
+
function buildConsensus(alignedSeq1, alignedSeq2) {
|
|
295
|
+
const chars = [];
|
|
296
|
+
for (let i = 0; i < alignedSeq1.length; i++) {
|
|
297
|
+
const a = alignedSeq1[i];
|
|
298
|
+
const b = alignedSeq2[i];
|
|
299
|
+
if (a !== '-' && b !== '-' && a.toUpperCase() === b.toUpperCase()) {
|
|
300
|
+
chars.push('|');
|
|
301
|
+
}
|
|
302
|
+
else if (a !== '-' && b !== '-' && getScore(a, b) > 0) {
|
|
303
|
+
chars.push(':');
|
|
304
|
+
}
|
|
305
|
+
else {
|
|
306
|
+
chars.push(' ');
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
return chars.join('');
|
|
310
|
+
}
|
|
311
|
+
/** The score of a sequence aligned to itself with no gaps. */
|
|
312
|
+
function selfScore(seq) {
|
|
313
|
+
let score = 0;
|
|
314
|
+
for (const c of seq) {
|
|
315
|
+
score += getScore(c, c);
|
|
316
|
+
}
|
|
317
|
+
return score;
|
|
318
|
+
}
|
|
319
|
+
function scoredAlignment(seq1, seq2, algorithm) {
|
|
320
|
+
const { alignedSeq1, alignedSeq2, score } = algorithm === 'smith_waterman'
|
|
321
|
+
? smithWaterman(seq1, seq2)
|
|
322
|
+
: needlemanWunsch(seq1, seq2);
|
|
323
|
+
return {
|
|
324
|
+
alignment: {
|
|
325
|
+
consensus: buildConsensus(alignedSeq1, alignedSeq2),
|
|
326
|
+
alns: [
|
|
327
|
+
{ id: 'a', seq: alignedSeq1 },
|
|
328
|
+
{ id: 'b', seq: alignedSeq2 },
|
|
329
|
+
],
|
|
330
|
+
},
|
|
331
|
+
score,
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
function runLocalAlignment(seq1, seq2, algorithm) {
|
|
335
|
+
return scoredAlignment(seq1, seq2, algorithm).alignment;
|
|
336
|
+
}
|
|
337
|
+
//# sourceMappingURL=pairwiseAlignment.js.map
|