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.
Files changed (172) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +148 -0
  3. package/dist/alignmentQuality.d.ts +58 -0
  4. package/dist/alignmentQuality.js +108 -0
  5. package/dist/alignmentQuality.js.map +1 -0
  6. package/dist/alphaFoldModels.d.ts +29 -0
  7. package/dist/alphaFoldModels.js +60 -0
  8. package/dist/alphaFoldModels.js.map +1 -0
  9. package/dist/caCoordsToPdb.d.ts +18 -0
  10. package/dist/caCoordsToPdb.js +95 -0
  11. package/dist/caCoordsToPdb.js.map +1 -0
  12. package/dist/chooseMappedEntity.d.ts +55 -0
  13. package/dist/chooseMappedEntity.js +140 -0
  14. package/dist/chooseMappedEntity.js.map +1 -0
  15. package/dist/coordinates.d.ts +66 -0
  16. package/dist/coordinates.js +66 -0
  17. package/dist/coordinates.js.map +1 -0
  18. package/dist/dbIds.d.ts +16 -0
  19. package/dist/dbIds.js +42 -0
  20. package/dist/dbIds.js.map +1 -0
  21. package/dist/extractPerResidueConfidence.d.ts +49 -0
  22. package/dist/extractPerResidueConfidence.js +42 -0
  23. package/dist/extractPerResidueConfidence.js.map +1 -0
  24. package/dist/extractStructureSequences.d.ts +142 -0
  25. package/dist/extractStructureSequences.js +217 -0
  26. package/dist/extractStructureSequences.js.map +1 -0
  27. package/dist/fetchUtils.d.ts +34 -0
  28. package/dist/fetchUtils.js +91 -0
  29. package/dist/fetchUtils.js.map +1 -0
  30. package/dist/index.d.ts +23 -0
  31. package/dist/index.js +46 -0
  32. package/dist/index.js.map +1 -0
  33. package/dist/invertMap.d.ts +2 -0
  34. package/dist/invertMap.js +8 -0
  35. package/dist/invertMap.js.map +1 -0
  36. package/dist/isoformRanking.d.ts +47 -0
  37. package/dist/isoformRanking.js +91 -0
  38. package/dist/isoformRanking.js.map +1 -0
  39. package/dist/mappings.d.ts +58 -0
  40. package/dist/mappings.js +193 -0
  41. package/dist/mappings.js.map +1 -0
  42. package/dist/package.json +1 -0
  43. package/dist/pairwiseAlignment.d.ts +35 -0
  44. package/dist/pairwiseAlignment.js +337 -0
  45. package/dist/pairwiseAlignment.js.map +1 -0
  46. package/dist/pdbUniProtMapping.d.ts +75 -0
  47. package/dist/pdbUniProtMapping.js +241 -0
  48. package/dist/pdbUniProtMapping.js.map +1 -0
  49. package/dist/pdbeBestStructures.d.ts +23 -0
  50. package/dist/pdbeBestStructures.js +79 -0
  51. package/dist/pdbeBestStructures.js.map +1 -0
  52. package/dist/pdbeEntryMolecules.d.ts +7 -0
  53. package/dist/pdbeEntryMolecules.js +39 -0
  54. package/dist/pdbeEntryMolecules.js.map +1 -0
  55. package/dist/siftsNumbering.d.ts +23 -0
  56. package/dist/siftsNumbering.js +44 -0
  57. package/dist/siftsNumbering.js.map +1 -0
  58. package/dist/stripStopCodon.d.ts +15 -0
  59. package/dist/stripStopCodon.js +24 -0
  60. package/dist/stripStopCodon.js.map +1 -0
  61. package/dist/structureFormat.d.ts +40 -0
  62. package/dist/structureFormat.js +54 -0
  63. package/dist/structureFormat.js.map +1 -0
  64. package/dist/structureSources.d.ts +28 -0
  65. package/dist/structureSources.js +76 -0
  66. package/dist/structureSources.js.map +1 -0
  67. package/dist/structureUrls.d.ts +54 -0
  68. package/dist/structureUrls.js +147 -0
  69. package/dist/structureUrls.js.map +1 -0
  70. package/dist/types.d.ts +14 -0
  71. package/dist/types.js +27 -0
  72. package/dist/types.js.map +1 -0
  73. package/dist/uniProtSearch.d.ts +32 -0
  74. package/dist/uniProtSearch.js +114 -0
  75. package/dist/uniProtSearch.js.map +1 -0
  76. package/esm/alignmentQuality.d.ts +58 -0
  77. package/esm/alignmentQuality.js +100 -0
  78. package/esm/alignmentQuality.js.map +1 -0
  79. package/esm/alphaFoldModels.d.ts +29 -0
  80. package/esm/alphaFoldModels.js +55 -0
  81. package/esm/alphaFoldModels.js.map +1 -0
  82. package/esm/caCoordsToPdb.d.ts +18 -0
  83. package/esm/caCoordsToPdb.js +91 -0
  84. package/esm/caCoordsToPdb.js.map +1 -0
  85. package/esm/chooseMappedEntity.d.ts +55 -0
  86. package/esm/chooseMappedEntity.js +134 -0
  87. package/esm/chooseMappedEntity.js.map +1 -0
  88. package/esm/coordinates.d.ts +66 -0
  89. package/esm/coordinates.js +58 -0
  90. package/esm/coordinates.js.map +1 -0
  91. package/esm/dbIds.d.ts +16 -0
  92. package/esm/dbIds.js +35 -0
  93. package/esm/dbIds.js.map +1 -0
  94. package/esm/extractPerResidueConfidence.d.ts +49 -0
  95. package/esm/extractPerResidueConfidence.js +38 -0
  96. package/esm/extractPerResidueConfidence.js.map +1 -0
  97. package/esm/extractStructureSequences.d.ts +142 -0
  98. package/esm/extractStructureSequences.js +205 -0
  99. package/esm/extractStructureSequences.js.map +1 -0
  100. package/esm/fetchUtils.d.ts +34 -0
  101. package/esm/fetchUtils.js +82 -0
  102. package/esm/fetchUtils.js.map +1 -0
  103. package/esm/index.d.ts +23 -0
  104. package/esm/index.js +30 -0
  105. package/esm/index.js.map +1 -0
  106. package/esm/invertMap.d.ts +2 -0
  107. package/esm/invertMap.js +5 -0
  108. package/esm/invertMap.js.map +1 -0
  109. package/esm/isoformRanking.d.ts +47 -0
  110. package/esm/isoformRanking.js +86 -0
  111. package/esm/isoformRanking.js.map +1 -0
  112. package/esm/mappings.d.ts +58 -0
  113. package/esm/mappings.js +179 -0
  114. package/esm/mappings.js.map +1 -0
  115. package/esm/pairwiseAlignment.d.ts +35 -0
  116. package/esm/pairwiseAlignment.js +328 -0
  117. package/esm/pairwiseAlignment.js.map +1 -0
  118. package/esm/pdbUniProtMapping.d.ts +75 -0
  119. package/esm/pdbUniProtMapping.js +231 -0
  120. package/esm/pdbUniProtMapping.js.map +1 -0
  121. package/esm/pdbeBestStructures.d.ts +23 -0
  122. package/esm/pdbeBestStructures.js +73 -0
  123. package/esm/pdbeBestStructures.js.map +1 -0
  124. package/esm/pdbeEntryMolecules.d.ts +7 -0
  125. package/esm/pdbeEntryMolecules.js +35 -0
  126. package/esm/pdbeEntryMolecules.js.map +1 -0
  127. package/esm/siftsNumbering.d.ts +23 -0
  128. package/esm/siftsNumbering.js +40 -0
  129. package/esm/siftsNumbering.js.map +1 -0
  130. package/esm/stripStopCodon.d.ts +15 -0
  131. package/esm/stripStopCodon.js +20 -0
  132. package/esm/stripStopCodon.js.map +1 -0
  133. package/esm/structureFormat.d.ts +40 -0
  134. package/esm/structureFormat.js +48 -0
  135. package/esm/structureFormat.js.map +1 -0
  136. package/esm/structureSources.d.ts +28 -0
  137. package/esm/structureSources.js +71 -0
  138. package/esm/structureSources.js.map +1 -0
  139. package/esm/structureUrls.d.ts +54 -0
  140. package/esm/structureUrls.js +134 -0
  141. package/esm/structureUrls.js.map +1 -0
  142. package/esm/types.d.ts +14 -0
  143. package/esm/types.js +23 -0
  144. package/esm/types.js.map +1 -0
  145. package/esm/uniProtSearch.d.ts +32 -0
  146. package/esm/uniProtSearch.js +110 -0
  147. package/esm/uniProtSearch.js.map +1 -0
  148. package/package.json +63 -0
  149. package/src/alignmentQuality.ts +132 -0
  150. package/src/alphaFoldModels.ts +91 -0
  151. package/src/caCoordsToPdb.ts +111 -0
  152. package/src/chooseMappedEntity.ts +198 -0
  153. package/src/coordinates.ts +119 -0
  154. package/src/dbIds.ts +46 -0
  155. package/src/extractPerResidueConfidence.ts +88 -0
  156. package/src/extractStructureSequences.ts +342 -0
  157. package/src/fetchUtils.ts +110 -0
  158. package/src/index.ts +34 -0
  159. package/src/invertMap.ts +4 -0
  160. package/src/isoformRanking.ts +139 -0
  161. package/src/mappings.ts +230 -0
  162. package/src/pairwiseAlignment.ts +423 -0
  163. package/src/pdbUniProtMapping.ts +320 -0
  164. package/src/pdbeBestStructures.ts +94 -0
  165. package/src/pdbeEntryMolecules.ts +37 -0
  166. package/src/siftsNumbering.ts +61 -0
  167. package/src/stripStopCodon.ts +20 -0
  168. package/src/structureFormat.ts +70 -0
  169. package/src/structureSources.ts +101 -0
  170. package/src/structureUrls.ts +171 -0
  171. package/src/types.ts +30 -0
  172. 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;
@@ -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":"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"}
@@ -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